// MarkupDlg.cpp : implementation file
//
// CMarkup Release 6.5 Lite
// Copyright (C) 1999-2003 First Objective Software, Inc. All rights reserved
// This entire notice must be retained in this source code
// Redistributing this source code requires written permission
// This software is provided "as is", with no warranty.
// Latest fixes enhancements and documentation at www.firstobject.com
#include "stdafx.h"
#include "MarkupApp.h"
#include "MarkupDlg.h"
#include "Markup.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMarkupDlg dialog
CMarkupDlg::CMarkupDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMarkupDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMarkupDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMarkupDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMarkupDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMarkupDlg, CDialog)
//{{AFX_MSG_MAP(CMarkupDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_BROWSE, OnButtonBrowse)
ON_BN_CLICKED(IDC_BUTTON_PARSE, OnButtonParse)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CMarkupDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
HCURSOR CMarkupDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
/////////////////////////////////////////////////////////////////////////////
// CMarkupDlg message handlers
BOOL CMarkupDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
m_nErrorCount = 0;
// Load settings
CString csFilename = AfxGetApp()->GetProfileString( _T("Settings"), _T("Filename"), _T("") );
if ( ! csFilename.IsEmpty() )
GetDlgItem( IDC_EDIT_FILE )->SetWindowText( csFilename );
CString csPos = AfxGetApp()->GetProfileString( _T("Settings"), _T("Position"), _T("") );
CPoint ptDlg;
if ( _stscanf( csPos, _T("%d,%d"), &ptDlg.x, &ptDlg.y ) == 2 )
{
CRect rect;
GetWindowRect( &rect );
if ( rect.Width() > 10 )
{
rect.OffsetRect( ptDlg.x - rect.left, ptDlg.y - rect.top );
MoveWindow( &rect );
}
}
// Determine version
CString csVersion, csV0, csV1;
CString csTitle;
csVersion.LoadString( ID_APP_VERSION );
AfxExtractSubString( csV0, csVersion, 0, ',' );
AfxExtractSubString( csV1, csVersion, 1, ',' );
CString csClass = _T("CMarkup Lite");
CString csBuild;
#if defined( _DEBUG )
csBuild += _T(" Debug");
#endif
#if defined( _UNICODE )
csBuild += _T(" Unicode");
#endif
#if defined( _MBCS )
csBuild += _T(" MBCS");
#endif
csTitle.Format( _T("%s %s.%s%s\r\n"), csClass, csV0, csV1, csBuild );
OutputTestResults( csTitle );
OutputParseResults( _T("") );
RunTest();
return TRUE; // return TRUE unless you set the focus to a control
}
void CMarkupDlg::OnDestroy()
{
// Save settings
CString csFilename;
GetDlgItem( IDC_EDIT_FILE )->GetWindowText( csFilename );
AfxGetApp()->WriteProfileString( _T("Settings"), _T("Filename"), csFilename );
CRect rect;
GetWindowRect( &rect );
CString csPos;
csPos.Format( _T("%d,%d"), rect.left, rect.top );
AfxGetApp()->WriteProfileString( _T("Settings"), _T("Position"), csPos );
CDialog::OnDestroy();
}
void CMarkupDlg::OutputTestResults( CString csMsg )
{
m_csTestResults += csMsg;
GetDlgItem( IDC_ST_TEST_RESULTS )->SetWindowText( m_csTestResults );
}
int CMarkupDlg::Alert( CString csMsg )
{
OutputTestResults( csMsg + _T("\r\n") );
++m_nErrorCount;
return -1;
}
void CMarkupDlg::StartCheckZone( CString csCheckZone )
{
m_nCheckCount = 0;
m_csCheckZone = csCheckZone;
}
int CMarkupDlg::Check( BOOL bCorrect )
{
++m_nCheckCount;
if ( ! bCorrect )
{
if ( m_csCheckZone.IsEmpty() )
m_csCheckZone = _T("Unknown Check Zone");
CString csMsg;
csMsg.Format( _T("Error: %s, check %d"), m_csCheckZone, m_nCheckCount );
return Alert( csMsg );
}
return 0;
}
int CMarkupDlg::RunTest()
{
// Implement tests here
CMarkup xml;
// Sample code from the article
StartCheckZone( _T("Article Tests") );
Check( xml.AddElem( _T("ORDER") ) );
Check( xml.AddChildElem( _T("ITEM") ) );
Check( xml.IntoElem() );
Check( xml.AddChildElem( _T("SN"), _T("132487A-J") ) );
Check( xml.AddChildElem( _T("NAME"), _T("crank casing") ) );
Check( xml.AddChildElem( _T("QTY"), _T("1") ) );
CString csXML = xml.GetDoc();
xml.SetDoc( csXML );
int nTotalQty = 0;
while ( xml.FindChildElem(_T("ITEM")) )
{
Check( xml.IntoElem() );
Check( xml.FindChildElem( _T("SN") ) );
CString csSN = xml.GetChildData();
Check( xml.FindChildElem( _T("QTY") ) );
nTotalQty += _ttoi( xml.GetChildData() );
Check( xml.OutOfElem() );
}
struct SampItem { LPCTSTR szSN; LPCTSTR szName; int nQty; } aItems[] =
{
_T("132487A-J"), _T("crank casing"), 1,
_T("4238764-A"), _T("bearing"), 15,
NULL, NULL, 0
};
struct SampPOS { LPCTSTR szType; LPCTSTR szName; LPCTSTR szTel; } poc =
{
_T("non-emergency"), _T("John Smith"), _T("555-1234")
};
xml.SetDoc( NULL );
Check( xml.AddElem( _T("ORDER") ) );
Check( xml.IntoElem() ); // inside ORDER
_TCHAR szQty[20];
for ( int nItem=0; aItems[nItem].szSN; ++nItem )
{
Check( xml.AddElem( _T("ITEM") ) );
Check( xml.IntoElem() ); // inside ITEM
Check( xml.AddElem( _T("SN"), aItems[nItem].szSN ) );
Check( xml.AddElem( _T("NAME"), aItems[nItem].szName ) );
Check( xml.AddElem( _T("QTY"), _itot(aItems[nItem].nQty,szQty,10) ) );
Check( xml.OutOfElem() ); // back out to ITEM level
}
Check( xml.AddElem( _T("SHIPMENT") ) );
Check( xml.IntoElem() ); // inside SHIPMENT
Check( xml.AddElem( _T("POC") ) );
Check( xml.SetAttrib( _T("type"), poc.szType ) );
Check( xml.IntoElem() ); // inside POC
Check( xml.AddElem( _T("NAME"), poc.szName ) );
Check( xml.AddElem( _T("TEL"), poc.szTel ) );
#if ! defined( _UNICODE )
xml.SetDoc( "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n" );
Check( xml.AddElem( "island", "Cura�ao" ) );
Check( xml.GetData() == "Cura�ao" );
#endif
// ORDER Test, simple XML example
StartCheckZone( _T("ORDER Test") );
xml.SetDoc( NULL );
Check( xml.AddElem( _T("ORDER") ) );
Check( xml.IntoElem() );
Check( xml.AddElem( _T("ITEM") ) );
Check( xml.AddChildElem( _T("NAME"), _T("carrots") ) );
Check( xml.AddChildElem( _T("QTY"), _T("1") ) );
Check( xml.AddChildElem( _T("PRICE"), _T(".98") ) );
Check( xml.AddChildAttrib( _T("unit"), _T("1 lb") ) );
Check( xml.AddElem( _T("ITEM") ) );
Check( xml.AddChildElem( _T("NAME"), _T("onions") ) );
Check( xml.AddChildElem( _T("QTY"), _T("1") ) );
Check( xml.AddChildElem( _T("PRICE"), _T("1.10") ) );
Check( xml.AddChildAttrib( _T("unit"), _T("3 lb bag") ) );
Check( xml.AddChildElem( _T("SUPPLIER"), _T("Hanover") ) );
// Create List
StartCheckZone( _T("List Test") );
CString csList;
xml.ResetPos();
Check( xml.FindElem( _T("ORDER") ) );
while ( xml.FindChildElem( _T("ITEM") ) )
{
xml.IntoElem();
xml.FindChildElem( _T("NAME") );
csList += xml.GetChildData();
csList += _T("\n");
xml.OutOfElem();
}
Check( csList == _T("carrots\nonions\n") );
// Car Test, add and replace randomly chosen attributes
StartCheckZone( _T("Random Car Part Test") );
srand( (unsigned)time( NULL ) );
struct CarTestData { _TCHAR* szLow; _TCHAR* szUp; _TCHAR* szMix; } aCT[] =
{
_T("up"), _T("SKY"), _T("Light"),
_T("down"), _T("FLOOR"), _T("Dust"),
_T("left"), _T("DOOR"), _T("Handle"),
_T("right"), _T("SEAT"), _T("Gear"),
_T("back"), _T("TRUNK"), _T("Tread"),
_T("forward"), _T("GRILL"), _T("Motor"),
_T(""), _T(""), _T("")
};
xml.SetDoc( _T("") );
xml.AddElem( _T("CAR") );
int nAt;
LPCTSTR szLow, szUp, szMix;
for ( nAt = 0; nAt < 20; ++nAt )
{
szLow = aCT[RandInt(6)].szLow;
szMix = aCT[RandInt(6)].szMix;
xml.SetAttrib( szLow, szMix );
Check( xml.GetAttrib(szLow) == szMix );
}
for ( int nPart=0; nPart<100; ++nPart )
{
xml.AddChildElem( aCT[RandInt(6)].szUp );
for ( nAt = 0; nAt < 8; ++nAt )
{
szLow = aCT[RandInt(6)].szLow;
szMix = aCT[RandInt(6)].szMix;
xml.SetChildAttrib( szLow, szMix );
Check( xml.GetChildAttrib(szLow) == szMix );
}
szLow = aCT[RandInt(6)].szLow;
szUp = aCT[RandInt(6)].szUp;
xml.SetChildAttrib( szLow, szUp );
Check( xml.GetChildAttrib(szLow) == szUp );
}
CString csCarDoc = xml.GetDoc();
Check( xml.SetDoc( csCarDoc ) );
// Comments Test, make sure it bypasses declaration, DTD, and comments
StartCheckZone( _T("Comments Test") );
CString csPTDoc =
_T("<?xml version=\"1.0\"?>\n")
_T("<!DOCTYPE PARSETEST [\n")
_T("<!ELEMENT PARSETEST (ITEM*)>\n")
_T("<!ATTLIST PARSETEST v CDATA \"\" s CDATA \"\">\n")
_T("<!ELEMENT ITEM ANY>\n")
_T("<!ATTLIST ITEM note CDATA \"\">\n")
_T("]>\n")
_T("<PARSETEST v=\"1\" s=\'6\'>\n")
_T("<!--- </P>& special chars -->\n")
_T("<ITEM note=\"Here's to "us"\"/>\n")
_T("<ITEM note=\"see data\">Here's to \"us\"</ITEM>\n")
_T("</PARSETEST>\n")
;
Check( xml.SetDoc( csPTDoc ) );
Check( xml.FindChildElem() );
Check( xml.GetAttrib( _T("v") ) == _T("1") );
Check( xml.GetChildAttrib(_T("note")) == _T("Here's to \"us\"") );
Check( xml.IntoElem() );
Check( xml.FindElem() );
Check( xml.GetData() == _T("Here's to \"us\"") );
// Depth First Traversal Test, loop through all elements
StartCheckZone( _T("Depth First Traversal Test") );
xml.SetDoc( _T("<A><B><C/><C/><C><D/></C></B><B/></A>") );
CString csListOfTagNames;
BOOL bFinished = FALSE;
if ( xml.FindElem() )
csListOfTagNames = xml.GetTagName();
if ( ! xml.FindChildElem() )
bFinished = TRUE;
while ( ! bFinished )
{
// Process Element
xml.IntoElem();
csListOfTagNames += xml.GetTagName();
// Next element (depth first)
BOOL bFound = xml.FindChildElem();
while ( ! bFound && ! bFinished )
{
if ( xml.OutOfElem() )
bFound = xml.FindChildElem();
else
bFinished = TRUE;
}
}
Check( csListOfTagNames == _T("ABCCCDB") );
// Success?
if ( ! m_nErrorCount )
this->OutputTestResults( _T("RunTest complete\r\n") );
return 0;
}
void CMarkupDlg::OnButtonBrowse()
{
LPCTSTR szTypes =
_T("XML Files (*.xml)|*.xml|")
_T("Text Files (*.txt)|*.txt|")
_T("All Files (*.*)|*.*||");
CFileDialog dlg( TRUE, _T("xml"), NULL, OFN_HIDEREADONLY, szTypes );
if ( dlg.DoModal() == IDCANCEL )
return;
CString csFilename = dlg.GetPathName();
GetDlgItem( IDC_EDIT_FILE )->SetWindowText( csFilename );
OutputParseResults( _T("") );
}
int CMarkupDlg::RandInt( int nNumber )
{
//
// Return an integer between 0 and nNumber
//
static BOOL bSeeded = FALSE;
if ( ! bSeeded )
{
srand( (unsigned)time( NULL ) );
bSeeded = TRUE;
}
// Sometimes rand() returns something close enough to 1 to make nRandom == nNumber
int nRandom = rand() * nNumber / RAND_MAX;
if ( nRandom == nNumber )
--nRandom;
return nRandom;
}
void CMarkupDlg::TimeStart()
{
// Keep track of time before operation
GetSystemTime( &m_stBefore );
}
int CMarkupDlg::TimeStop()
{
// Determine time span
SYSTEMTIME stAfter;
GetSystemTime( &stAfter );
int nBefore = m_stBefore.wMilliseconds + m_stBefore.wSecond * 1000 + m_stBefore.wMinute * 60000;
int nAfter = stAfter.wMilliseconds + stAfter.wSecond * 1000 + stAfter.wMinute * 60000;
int nDiff = nAfter - nBefore;
if ( m_stBefore.wHour < stAfter.wHour )
nDiff += 24*60000;
return nDiff;
}
void CMarkupDlg::OutputParseResults( CString csMsg )
{
GetDlgItem( IDC_ST_PARSE_RESULTS )->SetWindowText( csMsg );
}
void CMarkupDlg::OnButtonParse()
{
OutputParseResults( _T("") );
// Get pathname
CString csPath;
GetDlgItem( IDC_EDIT_FILE )->GetWindowText( csPath );
if ( csPath.IsEmpty() )
{
OnButtonBrowse();
GetDlgItem( IDC_EDIT_FILE )->GetWindowText( csPath );
if ( csPath.IsEmpty() )
return;
RedrawWindow();
}
// Open file
CWaitCursor wait;
TimeStart();
CString csText;
CString csNotes;
CFile file;
if ( ! file.Open( csPath, CFile::modeRead ) )
{
OutputParseResults( _T("unable to open file") );
return;
}
int nFileLen = (int)file.GetLength();
// Allocate buffer for binary file data
unsigned char* pBuffer = new unsigned char[nFileLen + 2];
nFileLen = file.Read( pBuffer, nFileLen );
file.Close();
pBuffer[nFileLen] = '\0';
pBuffer[nFileLen+1] = '\0'; // in case 2-byte encoded
// Windows Unicode file is detected if starts with FEFF
if ( pBuffer[0] == 0xff && pBuffer[1] == 0xfe )
{
// Contains byte order mark, so assume wide char content
// non _UNICODE builds should perform UCS-2 (wide char) to UTF-8 conversion here
csText = (LPCWSTR)(&pBuffer[2]);
csNotes += _T("File starts with hex FFFE, assumed to be wide char format. ");
}
else
{
// _UNICODE builds should perform UTF-8 to UCS-2 (wide char) conversion here
csText = (LPCSTR)pBuffer;
}
delete [] pBuffer;
int nTimeLoading = TimeStop();
// If it is too short, assume it got truncated due to non-text content
if ( csText.GetLength() < nFileLen / 2 - 20 )
{
OutputParseResults( _T("Error converting file to string (may contain binary data)") );
return;
}
// Parse
CMarkup xml;
TimeStart();
BOOL bResult = xml.SetDoc( csText );
int nTimeParsing = TimeStop();
// Display results
CString csMsg;
if ( bResult )
csMsg.Format( _T("Loaded in %s milliseconds, parsed in %s milliseconds\r\n")
_T("File size: %s bytes"),
AddNumSeps(nTimeLoading), AddNumSeps(nTimeParsing),
AddNumSeps(nFileLen) );
else
{
CString csError = xml.GetError();
csMsg.Format( _T("Error: %s\r\n")
_T("Loaded in %s milliseconds, parse failed in %s milliseconds\r\n")
_T("File size: %s bytes"),
csError,
AddNumSeps(nTimeLoading), AddNumSeps(nTimeParsing),
AddNumSeps(nFileLen) );
}
OutputParseResults( csMsg );
}