Click here to Skip to main content
15,886,199 members
Articles / Desktop Programming / ATL

SP Numeric Edit Control

Rate me:
Please Sign up or sign in to vote.
4.78/5 (11 votes)
16 Nov 200511 min read 74.7K   3.6K   36  
Masked numeric edit ActiveX control.
/////////////////////////////////////////////////////////////////////////////////////////
//	Project:		SP Data Formatting Library 1.5
//
//	File:			IntegerFormatter.cpp
//
//	Developer(s):	Sergei Pavlovsky
//					sergei_vp@hotmail.com
//					Copyright (c) 2004-2005
//
//	Description:	
//
//	Platforms:		Win32, ATL
//
//	This code may be used in compiled form in any way you desire. This file may be 
//	redistributed unmodified by any means PROVIDING it is not sold for profit without 
//	the authors written consent, and providing that this notice and the authors name 
//	is included. If the source code in this file is used in any commercial application 
//	then acknowledgement must be made to the author of this file (in whatever form 
//	you wish).
//
//	This file is provided "as is" with no expressed or implied warranty. The author 
//	accepts no liability for any damage/loss of business that this product may cause.
/////////////////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "../resource.h" // ???
#include "IntegerFormatter.h"

namespace SP
{

/////////////////////////////////////////////////////////////////////////////////////////
// CIntegerSegment class
/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////
// Operations: Common

UINT CIntegerSegment::_GetGeneralOperationErrorReason(EnumGeneralOperations enOp) const
{
	const UINT rgIDs[] = 
		{
			IDS_ERDF_COMPOSEINTSEGMENT,
			IDS_ERDF_GENERATEINTSEGMENT,
			IDS_ERDF_TRANSLATEINTSEGMENT,
			IDS_ERDF_TRANSLATEINTSEGMENT,
			0,
			0,
			0,
			0
		};

	ATLASSERT( enOp < sizeof(rgIDs)/sizeof(UINT) );

	return rgIDs[enOp];
}

/////////////////////////////////////////////////////////////////////////////////////////
// Helpers: Expression

UINT_PTR CIntegerSegment::ComposeTraitsToken(CNumericCompositionCtx& ctx, 
											 CNumericFormatTraits::TokensEnum enToken,
											 LPTSTR& lpBuf, UINT_PTR& cchBuf) const
{
	ATLASSERT( enToken );
	ATLASSERT( !::IsBadWritePtr(lpBuf, cchBuf * sizeof(TCHAR)) );

	if ( enToken == CNumericFormatTraits::TK_VALUE )
	{
		CIntegerCompositionCtx& ctxIEC = static_cast<CIntegerCompositionCtx&>(ctx);

		UINT_PTR cchResult = 0;

		LPTSTR lpBufPos = lpBuf + cchBuf;

		// Add first entry
		UINT_PTR cMinDigits = ctxIEC.GetMinIntegerDigits();

		// Add groups
		for ( UINT_PTR i = 0; i < ctxIEC.GetGroupsCount(); )
		{
			const BYTE cGroupDigits = ctxIEC.GetGroupSizeAt(i);
			const bool bFirstGroup = cchResult == 0;

			TCHAR chSrndBack;
			TCHAR chSrndFore;

			if ( bFirstGroup || cMinDigits )
			{
				chSrndBack = chSrndFore = _T('\x0');
			}
			else
			{
				if ( ctxIEC.IsLastGroupRepeated() && i == ctxIEC.GetGroupsCount() - 1 )
				{
					chSrndBack = TN_CLOSEREPEAT;
					chSrndFore = TN_OPENREPEAT;
				}
				else
				{
					chSrndBack = TN_CLOSEOPTIONAL;
					chSrndFore = TN_OPENOPTIONAL;
				}
			}

			// Write symbol opening group 
			if ( chSrndFore )
				cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, chSrndFore);

			if ( cGroupDigits )
			{
				// Write group separator
				if ( !bFirstGroup )
					cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, 
														  TN_THOUSANDSSEPARATOR);

				// Write digit symbols
				for ( BYTE j = 0; j < cGroupDigits; j++ )
				{
					if ( cMinDigits ) 
					{
						cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, TN_ZERO);
						cMinDigits--;
					}
					else
					{
						cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, TN_DIGIT);					
					}
				}
			}
			else
			{
				// Write digit symbols
				if ( cMinDigits ) 
				{
					cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, TN_ZERO);
					cMinDigits--;
				}
				else
				{
					cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, TN_DIGIT);					
				}
			}

			// Write symbol closing group 
			if ( chSrndBack )
				cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, chSrndBack);

			if ( i + 1 < ctxIEC.GetGroupsCount() || !ctxIEC.IsLastGroupRepeated() || 
				 chSrndBack == TN_CLOSEREPEAT )
			{
				i++;
			}
		}

		// Write the rest of non-optional digit symbols
		while ( cMinDigits )
		{		
			cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, TN_ZERO);
			cMinDigits--;
		}

		// If last group is not continued and number of digits is unlimited. 
		// we should add final digit to be repeated.
		if ( ctxIEC.GetMaxIntegerDigits() == DC_UNLIMITED && !ctxIEC.IsLastGroupRepeated() )
		{
			// Write symbol opening group 
			cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, TN_OPENREPEAT);

			// Write digit symbols
			cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, TN_DIGIT);

			// Write symbol closing group 
			cchResult += CFormatter::WriteTokenBwd(ctx, lpBufPos, cchBuf, TN_CLOSEREPEAT);
		}

		if ( lpBuf )
		{
			::MoveMemory(lpBuf, lpBufPos, cchResult * sizeof(TCHAR));
			lpBuf += cchResult;
		}

		return cchResult;
	}

	return CNumericDigitalRTLSegment::ComposeTraitsToken(ctx, enToken, lpBuf, cchBuf);
}

/////////////////////////////////////////////////////////////////////////////////////////
// Operations: Expression

UINT_PTR CIntegerSegment::ComposeExpression(CCompositionCtx& ctx, 
											LPTSTR& lpBuf, UINT_PTR& cchBuf) const
{
	ATLASSERT( !::IsBadReadPtr(&ctx, sizeof(CIntegerCompositionCtx)) );
	ATLASSERT( !::IsBadWritePtr(lpBuf, cchBuf * sizeof(TCHAR)) );

	// Update context
	CIntegerCompositionCtx& ctxC = static_cast<CIntegerCompositionCtx&>(ctx);
	ctxC.ChangeSegment(this);

	UINT_PTR cchResult;

	__try
	{
		cchResult = ComposeTraitsToken(ctxC, CNumericFormatTraits::TK_VALUE, 
									   lpBuf, cchBuf);
	}
	__finally
	{
		// Restore previous context
		ctx.DiscardSegment();
	}

	return cchResult;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Operations: Formatting & scanning

UINT_PTR CIntegerSegment::Format(CNumericDataCtx& ctx, 
								 LPCTSTR lpcValue, UINT_PTR cchValue,
								 LPTSTR& lpBuffer, UINT_PTR& cchBuffer) const
{
	ATLASSERT( !::IsBadReadPtr(lpcValue, cchValue * sizeof(TCHAR)) );
	ATLASSERT( !::IsBadWritePtr(lpBuffer, cchBuffer * sizeof(TCHAR)) );

	CIntegerDataCtx& ctxD = static_cast<CIntegerDataCtx&>(ctx);
	ctxD.ChangeSegment(this);

	UINT_PTR cchResult;

	__try
	{
		cchResult = _Format(ctx, lpcValue + cchValue, cchValue,
							lpBuffer + cchBuffer, cchBuffer);

		if ( lpBuffer )
		{
			MoveMemory(lpBuffer, lpBuffer + cchBuffer - cchResult, 
					   cchResult * sizeof(TCHAR));

			lpBuffer += cchResult;
			cchBuffer -= cchResult;
		}
	}
	__finally
	{
		ctx.DiscardSegment();
	}

	return cchResult;
}

UINT_PTR CIntegerSegment::Scan(CNumericDataCtx& ctx, LPCTSTR lpcText, UINT_PTR cchText, 
							   LPTSTR& lpBuffer, UINT_PTR& cchBuffer) const
{
	CIntegerDataCtx& ctxD = static_cast<CIntegerDataCtx&>(ctx);
	ctxD.ChangeSegment(this);

	UINT_PTR cchResult = 0;

	__try
	{
		LPTSTR lpBuf = lpBuffer;
		UINT_PTR cchBuf = cchBuffer;

		// Write sign
		if ( ctxD.GetSign() < 0 )
		{
			const TCHAR cchSign = SV_MINUS;
			cchResult += CFormatter::WriteEntryFwd(ctxD, lpBuf, cchBuf, &cchSign, 1);
		}

		// Write digits
		UINT_PTR cchWritten = _Scan(ctxD, lpcText + cchText, cchText, 
									lpBuf + cchBuf, cchBuf);

		if ( cchWritten == STATUS_FALSE ) // ??? Error
		{
			cchResult = STATUS_FALSE;
		}
		else
		{
			cchResult += cchWritten;

			if ( lpBuffer ) 
			{
				::MoveMemory(lpBuf, lpBuf + cchBuf - cchWritten, 
							cchWritten * sizeof(TCHAR));

				lpBuffer += cchResult;
				cchBuffer -= cchResult;
			}
		}
	}
	__finally
	{
		ctx.DiscardSegment();
	}

	return cchResult;
}

/////////////////////////////////////////////////////////////////////////////////////////
// CIntegerLiteralSegment class
/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////
// Operations: Common

UINT CIntegerLiteralSegment::_GetGeneralOperationErrorReason(
													EnumGeneralOperations enOp) const
{
	const UINT rgIDs[] = 
		{
			IDS_ERDF_COMPOSESEGMENT,
			IDS_ERDF_GENERATESEGMENT,
			IDS_ERDF_TRANSLATESEGMENT,
			IDS_ERDF_TRANSLATESEGMENT,
			0,
			0,
			0,
			0
		};

	ATLASSERT( enOp < sizeof(rgIDs)/sizeof(UINT) );

	return rgIDs[enOp];
}

/////////////////////////////////////////////////////////////////////////////////////////
// CIntegerDigitalPattern class implementation
/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////
// Constants

const UINT CIntegerDigitalPattern::ms_aDigitalSegmentIDs[] = 
{ 
	SG_INTEGER
};

#ifdef _DEBUG

/////////////////////////////////////////////////////////////////////////////////////////
// Debug

CTString CIntegerDigitalPattern::DumpContent() const
{
	CTString csText;
/*	bool bResult = csText.Allocate(64 + 32 * m_vecIntegerCommands.size());
	ATLASSERT( bResult );

	_stprintf(csText, _T("Commands: Capacity: %u\r\n"), 
			  GetIntegerDigitCapacity());

	for ( UINT_PTR i = 0; i < m_vecIntegerCommands.size();  i++ )
	{			
		const CToken& cmd = m_vecIntegerCommands[i];

		CTString csNumber;
		csNumber.Allocate(16);

		_stprintf(csNumber, _T("%03u: "), i);

		csText += (csNumber + cmd.DumpContent() + _T("\r\n"));
	}
*/
	return csText;
}

#endif // _DEBUG

/////////////////////////////////////////////////////////////////////////////////////////
// Helpers: Common

UINT_PTR CIntegerDigitalPattern::GetDigitalSegments(
								const CNumericDigitalSegment** prgSegments) const
{
	const UINT_PTR cSegments = sizeof(ms_aDigitalSegmentIDs)/sizeof(UINT);

	ATLASSERT( !prgSegments || !::IsBadWritePtr(prgSegments, 
									cSegments * sizeof(CNumericDigitalSegment*)) );

	if ( prgSegments )
	{
		prgSegments[0] = &m_segInteger;
	}

	return cSegments;
}

UINT_PTR CIntegerDigitalPattern::GetDigitalSegments(
									CNumericDigitalSegment** prgSegments)
{
	const UINT_PTR cSegments = sizeof(ms_aDigitalSegmentIDs)/sizeof(UINT);

	ATLASSERT( !prgSegments || !::IsBadWritePtr(prgSegments, 
									cSegments * sizeof(CNumericDigitalSegment*)) );

	if ( prgSegments )
	{
		prgSegments[0] = &m_segInteger;
	}

	return cSegments;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Helpers: Expression

bool CIntegerDigitalPattern::ParseIExpression(CExpressionCtx& ctx, LPCTSTR lpcSrc, 
											  UINT_PTR cchSrc, IExpression* pExpr)
{
	ATLASSERT( !::IsBadReadPtr(lpcSrc, cchSrc * sizeof(TCHAR)) );
	ATLASSERT( !::IsBadReadPtr(pExpr, sizeof(IExpression)) );

	bool bResult = ParseVExpression(ctx, lpcSrc, cchSrc, pExpr);
	ATLASSERT( bResult );
	if ( !bResult )   
		return false;

	LPCTSTR lpVBegin = pExpr->lpcPrefix 
							? pExpr->lpcPrefix + pExpr->cchPrefix + 1 
							: lpcSrc;

	LPCTSTR lpVEnd = pExpr->lpcSuffix 
							? pExpr->lpcSuffix  - 1
							: lpcSrc + cchSrc;

	pExpr->lpcInteger = lpVBegin;
	pExpr->cchInteger = lpVEnd - lpVBegin;
	pExpr->cIntegerBaseLevel = 0;

	return true;
}

bool CIntegerDigitalPattern::ParseExpression(CExpressionCtx& ctx, 
											 LPCTSTR lpcSrc, UINT_PTR cchSrc,
											 SExpression* prgSExpressions) const
{
	ATLASSERT( !::IsBadReadPtr(lpcSrc, cchSrc * sizeof(TCHAR)) );
	ATLASSERT( !::IsBadReadPtr(prgSExpressions, 
							   (GetDigitalSegments(NULL) + 2) * sizeof(SExpression)) );

	// Parse expression segments
	IExpression iexp;
	bool bResult = ParseIExpression(ctx, lpcSrc, cchSrc, &iexp);
	ATLASSERT( bResult );
	if ( !bResult ) 
	{
		const UINT eReasonID = _GetGeneralOperationErrorReason(GO_PARSEEXPRESSION);

		SP::AccountError(SP::AE_LOG|SP::AE_SETMSG, IDS_ELS_SPCONVERSION, 2, 
						 eReasonID);
		return false;
	}

	// Add segments information to the vector
	prgSExpressions[0].lpcSergment = iexp.lpcPrefix;
	prgSExpressions[0].cchSergment = iexp.cchPrefix;
	prgSExpressions[0].cBaseLevel = 0;

	prgSExpressions[1].lpcSergment = iexp.lpcInteger;
	prgSExpressions[1].cchSergment = iexp.cchInteger;
	prgSExpressions[1].cBaseLevel =  iexp.cIntegerBaseLevel;

	prgSExpressions[2].lpcSergment = iexp.lpcSuffix;
	prgSExpressions[2].cchSergment = iexp.cchSuffix;
	prgSExpressions[2].cBaseLevel = 0;

	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Operations: Expression

UINT_PTR CIntegerDigitalPattern::ComposeExpression(CCompositionCtx& ctx, LPTSTR& lpBuf, 
												   UINT_PTR& cchBuf) const
{
	ATLASSERT( !::IsBadWritePtr(lpBuf, cchBuf * sizeof(TCHAR)) );
	
	CIntegerCompositionCtx& ctxC = static_cast<CIntegerCompositionCtx&>(ctx);
	ctxC.ChangePattern(this);

	UINT_PTR cchResult;

	__try
	{
		 cchResult = Compose(ctxC, lpBuf, cchBuf);
	}
	__finally
	{
		ctx.DiscardPattern();
	}

	return cchResult;
}

/////////////////////////////////////////////////////////////////////////////////////////
// Helpers: Formatting & scanning

void CIntegerDigitalPattern::ParseStdTextIValue(CIntegerDataCtx& ctx,  
												LPCTSTR lpcValue, UINT_PTR cchValue, 
												IValueParts* pVP) const
{
	ATLASSERT( !::IsBadReadPtr(lpcValue, cchValue * sizeof(TCHAR)) );
	ATLASSERT( !::IsBadWritePtr(pVP, sizeof(IValueParts)) );

	pVP->lpcInteger = lpcValue;
	pVP->cchInteger = cchValue;

	// Define sign
	if ( pVP->cchInteger )
	{
		switch ( *pVP->lpcInteger )
		{
		case SV_MINUS:
			pVP->nSign = -1;
			pVP->lpcInteger++;
			pVP->cchInteger--;
			break;

		case SV_PLUS:
			pVP->nSign = 1;
			pVP->lpcInteger++;
			pVP->cchInteger--;
			break;

		default:
			pVP->nSign = 0;
		}
	}
	else
	{
		pVP->nSign = 0;
	}

	// Skip sign and spaces in the beginning
	while ( *pVP->lpcInteger == SV_ZERO )
	{
		pVP->lpcInteger++;
		pVP->cchInteger--;
	}
}

void CIntegerDigitalPattern::ParseTextIValue(CIntegerDataCtx& ctx, 
											 LPCTSTR lpcText, UINT_PTR cchText, 
											 IValueParts* pVP) const
{
	ATLASSERT( !::IsBadReadPtr(lpcText, cchText * sizeof(TCHAR)) );
	ATLASSERT( !::IsBadWritePtr(pVP, sizeof(IValueParts)) );

	pVP->lpcInteger = lpcText;
	pVP->cchInteger = cchText;
}

UINT_PTR CIntegerDigitalPattern::_Format(CIntegerDataCtx& ctx, 
										 LPCTSTR lpcValue, UINT_PTR cchValue,
										 LPTSTR lpBuffer, UINT_PTR cchBuffer) const
{
	ATLASSERT( !::IsBadReadPtr(lpcValue, cchValue * sizeof(TCHAR)) );
	ATLASSERT( !::IsBadWritePtr(lpBuffer, cchBuffer * sizeof(TCHAR)) );

	IValueParts vp;
	ParseStdTextValue(ctx, lpcValue, cchValue, &vp);

	vp.lpcInteger = vp.lpcPrefix + vp.cchPrefix;
	vp.cchInteger = vp.lpcSuffix - vp.lpcInteger;

	ParseStdTextIValue(ctx, vp.lpcInteger, vp.cchInteger, &vp);

	UINT_PTR cchResult = 0;

	// Format prefix part
	cchResult += FormatPrefix(ctx, lpBuffer, cchBuffer);

	// Format integer part
	cchResult += FormatInteger(ctx, vp.nSign, vp.lpcInteger, vp.cchInteger, 
							   lpBuffer, cchBuffer);

	// Format suffix part
	cchResult += FormatSufix(ctx, lpBuffer, cchBuffer);

	return cchResult;
}

UINT_PTR CIntegerDigitalPattern::_Scan(CIntegerDataCtx& ctx, 
									   LPCTSTR lpcText, UINT_PTR cchText, 
									   LPTSTR lpBuffer, UINT_PTR cchBuffer) const
{
	ATLASSERT( !::IsBadReadPtr(lpcText, cchText * sizeof(TCHAR)) );
	ATLASSERT( !::IsBadWritePtr(lpBuffer, cchBuffer * sizeof(TCHAR)) );

	// Parse value text
	IValueParts vp;
	if ( !ParseTextValue(ctx, lpcText, cchText, &vp) )
		return STATUS_FALSE;

	vp.lpcInteger = vp.lpcPrefix + vp.cchPrefix;
	vp.cchInteger = vp.lpcSuffix - vp.lpcInteger;

	ParseTextIValue(ctx, vp.lpcInteger, vp.cchInteger, &vp);

	// Text with empty numeric parts cannot define a number. Check it.
	if ( !vp.cchInteger )
		return STATUS_FALSE;

	// Scan all digital segments
	return ScanInteger(ctx, vp.lpcInteger, vp.cchInteger, lpBuffer, cchBuffer);
}

/////////////////////////////////////////////////////////////////////////////////////////
// CIntegerLiteralPattern class
/////////////////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////////////////
// CIntegerNullPattern class implementation
/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////
// Operarions: Common

UINT CIntegerNullPattern::_GetGeneralOperationErrorReason(
													EnumGeneralOperations enOp) const
{
	const UINT rgIDs[] = 
		{
			IDS_ERDF_COMPOSENULLPATTERN,
			IDS_ERDF_GENERATENULLPATTERN,
			IDS_ERDF_PARSENULLPATTERN,
			IDS_ERDF_TRANSLATENULLPATTERN,
			0,
			0,
			0,
			0
		};

	ATLASSERT( enOp < sizeof(rgIDs)/sizeof(UINT) );

	return rgIDs[enOp];
}

/////////////////////////////////////////////////////////////////////////////////////////
// Operations: Formatting & scanning

UINT_PTR CIntegerNullPattern::Format(CDataCtx& ctx, const void* lpcValue, 
									 LPTSTR lpBuffer, UINT_PTR cchBuffer) const
{
	ATLASSERT( !::IsBadWritePtr(lpBuffer, cchBuffer * sizeof(TCHAR)) );

	CIntegerDataCtx& ctxD = static_cast<CIntegerDataCtx&>(ctx);
	ctxD.ChangePattern(this);		

	UINT_PTR cchResult;

	__try
	{
		cchResult = m_segment.Format(ctxD, lpBuffer, cchBuffer);
	}
	__finally
	{
		ctx.DiscardPattern();
	}

	return cchResult;
}

UINT_PTR CIntegerNullPattern::Matches(CDataCtx& ctx, LPCTSTR lpcText, 
									  UINT_PTR cchText) const
{
	ATLASSERT( !::IsBadReadPtr(lpcText, cchText * sizeof(TCHAR)) );

	CIntegerDataCtx& ctxD = static_cast<CIntegerDataCtx&>(ctx);
	ctxD.ChangePattern(this);

	UINT_PTR cchResult;

	__try
	{
		cchResult = m_segment.Check(ctxD, lpcText, cchText) 
						? STATUS_TRUE : STATUS_FALSE;
	}
	__finally
	{
		ctx.DiscardPattern();
	}

	return cchResult;
}

UINT_PTR CIntegerNullPattern::Scan(CDataCtx& ctx, LPCTSTR lpcText, UINT_PTR cchText, 
							       void* lpValue, bool* pbNotNull) const
{
	ATLASSERT( !::IsBadReadPtr(lpcText, cchText * sizeof(TCHAR)) );
	ATLASSERT( !::IsBadWritePtr(pbNotNull, sizeof(bool)) );

	CIntegerDataCtx& ctxD = static_cast<CIntegerDataCtx&>(ctx);
	ctxD.ChangePattern(this);		

	UINT_PTR cchResult;

	__try
	{
		if ( m_segment.Check(ctxD, lpcText, cchText) )
		{				
			*pbNotNull = false;
			
			cchResult = STATUS_TRUE;
		}
		else
		{
			cchResult = STATUS_FALSE;
		}
	}
	__finally
	{
		ctx.DiscardPattern();
	}

	return cchResult;
}

/////////////////////////////////////////////////////////////////////////////////////////
// CIntegerFormatter class implementation
/////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////
// Operations: Formatting & scanning

UINT_PTR CIntegerFormatter::Format(const void* lpcValue, 
								   LPTSTR lpBuffer, UINT_PTR cchBuffer) const
{
	ATLASSERT( !::IsBadWritePtr(lpBuffer, cchBuffer * sizeof(TCHAR)) );

	// Create context and format the value.
	return _Format(CIntegerDataCtx(this), lpcValue, lpBuffer, cchBuffer);
}

UINT_PTR CIntegerFormatter::Matches(LPCTSTR lpcText, UINT_PTR cchText) const
{
	ATLASSERT( !::IsBadReadPtr(lpcText, cchText * sizeof(TCHAR)) );
	
	// Create context and check if the value matches to one of the patterns
	return _Matches(CIntegerDataCtx(this), lpcText, cchText);
}

UINT_PTR CIntegerFormatter::Scan(LPCTSTR lpcText, UINT_PTR cchText, 
								 void* lpValue, bool* pbNotNull) const
{
	ATLASSERT( !::IsBadReadPtr(lpcText, sizeof(TCHAR) * cchText) );

	// Create context and try to scan the value using one of the patterns
	return _Scan(CIntegerDataCtx(this), lpcText, cchText, lpValue, pbNotNull);
}

}; // namespace SP

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions