You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
338 lines
7.9 KiB
338 lines
7.9 KiB
// xmlint.cpp : Defines the entry point for the console application.
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
|
|
//====================================================================================
|
|
// Generic wild-card file finder that calls back to specified function with
|
|
// given void* arguments.
|
|
|
|
typedef HRESULT (*FILECALLBACK)(WCHAR* pszFile, void* arg);
|
|
|
|
WCHAR* WideString(const char* str)
|
|
{
|
|
if (str == NULL)
|
|
return NULL;
|
|
WCHAR * result = new WCHAR[strlen(str) + 1];
|
|
WCHAR* p = result;
|
|
while (*str)
|
|
*p++ = (WCHAR)*str++;
|
|
*p = 0;
|
|
return result;
|
|
}
|
|
|
|
int ProcessFiles(const char* pszFiles, FILECALLBACK pFunc, void* pArgs)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
int i;
|
|
|
|
WCHAR* wszArg = WideString(pszFiles);
|
|
WIN32_FIND_DATA FindFileData;
|
|
HANDLE handle = ::FindFirstFile(wszArg, &FindFileData);
|
|
int failed = 0;
|
|
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
{
|
|
// Then maybe it's a URL.
|
|
hr = (*pFunc)(wszArg, pArgs);
|
|
if (hr != 0) failed++;
|
|
goto CleanUp;
|
|
}
|
|
for ( i = wcslen(wszArg)-1; i >= 0 && wszArg[i] != '\\'; i--)
|
|
{
|
|
wszArg[i] = 0;
|
|
}
|
|
|
|
while (handle != INVALID_HANDLE_VALUE)
|
|
{
|
|
ULONG len1 = wcslen(wszArg);
|
|
ULONG len2 = wcslen(FindFileData.cFileName);
|
|
WCHAR* buffer = new WCHAR[len1 + len2 + 1];
|
|
if (buffer == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto CleanUp;
|
|
}
|
|
memcpy(buffer, wszArg, sizeof(WCHAR) * len1);
|
|
memcpy(&buffer[len1], FindFileData.cFileName, sizeof(WCHAR) * len2);
|
|
buffer[len1+len2] = '\0';
|
|
|
|
hr = (*pFunc)(buffer, pArgs);
|
|
|
|
if (hr != 0) failed++;
|
|
|
|
delete[] buffer;
|
|
|
|
if (! ::FindNextFile(handle, &FindFileData))
|
|
break;
|
|
}
|
|
if (handle != INVALID_HANDLE_VALUE)
|
|
::FindClose(handle);
|
|
|
|
CleanUp:
|
|
delete wszArg;
|
|
|
|
return failed;
|
|
}
|
|
|
|
struct XMLArgs
|
|
{
|
|
public:
|
|
XMLArgs()
|
|
{
|
|
pDOM = NULL;
|
|
pIE4 = NULL;
|
|
}
|
|
|
|
IXMLDOMDocument* pDOM;
|
|
IXMLDocument* pIE4;
|
|
};
|
|
|
|
|
|
void FormatError(BSTR bstrReason, BSTR bstrURL, BSTR bstrText, long lLine, long lPos)
|
|
{
|
|
if (bstrReason)
|
|
{
|
|
printf("\t%S", bstrReason);
|
|
}
|
|
if (bstrURL)
|
|
{
|
|
printf("\tURL: %S\n", bstrURL);
|
|
}
|
|
|
|
if (lLine > 0 && bstrText)
|
|
{
|
|
printf("\tLine %5.5ld: ", lLine);
|
|
|
|
long lLen = ::SysStringLen(bstrText);
|
|
for (int i = 0; i < lLen; i++)
|
|
{
|
|
if (bstrText[i] == '\t')
|
|
printf(" ");
|
|
else
|
|
printf("%C", bstrText[i]);
|
|
}
|
|
printf("\n");
|
|
|
|
if (lPos > 0 || lLen > 0)
|
|
{
|
|
printf("\tPos %5.5d: ", lPos);
|
|
for (int i = 1; i < lPos; i++)
|
|
{
|
|
printf("-");
|
|
}
|
|
printf("^\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void PrintIE4Error(IXMLDocument* pDoc)
|
|
{
|
|
IXMLError *pError = NULL ;
|
|
XML_ERROR xmle = { 0, 0, 0, 0, 0, 0 };
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = pDoc->QueryInterface(IID_IXMLError, (void **)&pError);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Error getting error information\n");
|
|
goto done;
|
|
}
|
|
|
|
hr = pError->GetErrorInfo(&xmle);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Error getting error information\n");
|
|
goto done;
|
|
}
|
|
|
|
FormatError(xmle._pszFound, NULL, xmle._pchBuf, xmle._nLine, xmle._ich);
|
|
|
|
done:
|
|
SysFreeString(xmle._pszFound);
|
|
SysFreeString(xmle._pszExpected);
|
|
SysFreeString(xmle._pchBuf);
|
|
if (pError) pError->Release();
|
|
}
|
|
|
|
void PrintDOMError(IXMLDOMDocument* pDoc)
|
|
{
|
|
IXMLDOMParseError* pError;
|
|
BSTR bstrReason = NULL;
|
|
BSTR bstrText = NULL;
|
|
BSTR bstrURL = NULL;
|
|
long lPos,lLine = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = pDoc->get_parseError( &pError);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Error getting error information\n");
|
|
goto done;
|
|
}
|
|
|
|
pError->get_reason(&bstrReason);
|
|
pError->get_url(&bstrURL);
|
|
pError->get_line(&lLine);
|
|
pError->get_srcText(&bstrText);
|
|
pError->get_linepos(&lPos);
|
|
|
|
FormatError(bstrReason, bstrURL, bstrText, lLine, lPos);
|
|
|
|
done:
|
|
SysFreeString( bstrReason);
|
|
SysFreeString( bstrText);
|
|
SysFreeString( bstrURL);
|
|
if (pError) pError->Release();
|
|
}
|
|
|
|
HRESULT xmlint(WCHAR* pszFile, void* arg)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
XMLArgs* pArgs = (XMLArgs*)arg;
|
|
|
|
printf("%S\n", pszFile);
|
|
|
|
if (pArgs->pIE4)
|
|
{
|
|
IXMLElement * root;
|
|
hr = pArgs->pIE4->put_URL(pszFile);
|
|
pArgs->pIE4->get_root(&root);
|
|
if (FAILED(hr) || ! root)
|
|
{
|
|
PrintIE4Error(pArgs->pIE4);
|
|
}
|
|
if (root) root->Release();
|
|
}
|
|
else
|
|
{
|
|
VARIANT_BOOL bSuccess;
|
|
VARIANT url;
|
|
url.vt = VT_BSTR;
|
|
V_BSTR(&url) = ::SysAllocString(pszFile);
|
|
hr = pArgs->pDOM->load(url, &bSuccess);
|
|
VariantClear(&url);
|
|
if (FAILED(hr) || bSuccess == VARIANT_FALSE)
|
|
{
|
|
PrintDOMError(pArgs->pDOM);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
void PrintUsage()
|
|
{
|
|
printf("Usage: xmlint [options] filename(s)\n");
|
|
printf("Checks well-formedness and validation constraints for one or more XML documents.\n");
|
|
printf("File names can contain wild cards for validating multiple files (e.g. \"*.xml\")\n");
|
|
printf("Example:\n");
|
|
printf("\txmlint *.xml\n\n");
|
|
printf("Checks that all files ending with .xml are valid xml files.\n\n");
|
|
printf("Options:\n");
|
|
printf("-w\tOnly perform well-formedness check (no DTD validation)\n");
|
|
printf("-ie4\tRun in IE4 compatibility mode (instead of new DOM mode)\n");
|
|
}
|
|
|
|
int __cdecl main(int argc, char* argv[])
|
|
{
|
|
int count = 0;
|
|
XMLArgs args;
|
|
bool fIE4 = false;
|
|
bool fValidate = true;
|
|
bool fPause = false;
|
|
HRESULT hr;
|
|
int rc = 0;
|
|
|
|
CoInitialize(NULL);
|
|
|
|
for (int i = 1; i < argc; i++)
|
|
{
|
|
char* pszArg = argv[i];
|
|
if (*pszArg == '-')
|
|
{
|
|
if (strcmp(pszArg,"-ie4") == 0)
|
|
{
|
|
fIE4 = true;
|
|
}
|
|
else
|
|
{
|
|
switch (pszArg[1])
|
|
{
|
|
case 'w':
|
|
fValidate = false;
|
|
break;
|
|
case 'p':
|
|
fPause = true;
|
|
break;
|
|
default:
|
|
PrintUsage();
|
|
rc = 1;
|
|
goto Error;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (count == 0)
|
|
{
|
|
PrintUsage();
|
|
rc = 1;
|
|
goto Error;
|
|
}
|
|
|
|
if (fIE4)
|
|
{
|
|
hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IXMLDocument, (void**)&(args.pIE4));
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Error co-creating IE4 XML Document");
|
|
goto Error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IXMLDOMDocument, (void**)&(args.pDOM));
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Error co-creating XML DOM Document");
|
|
goto Error;
|
|
}
|
|
|
|
args.pDOM->put_validateOnParse(fValidate ? VARIANT_TRUE : VARIANT_FALSE);
|
|
args.pDOM->put_async(VARIANT_FALSE);
|
|
}
|
|
|
|
if (fPause)
|
|
{
|
|
printf("Press any key to continue...");
|
|
getchar();
|
|
}
|
|
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
char* pszArg = argv[i];
|
|
if (*pszArg != '-')
|
|
{
|
|
rc += ProcessFiles(pszArg, xmlint, &args);
|
|
}
|
|
}
|
|
|
|
Error:
|
|
if (args.pDOM) args.pDOM->Release();
|
|
if (args.pIE4) args.pIE4->Release();
|
|
|
|
if (fPause)
|
|
{
|
|
printf("Press any key to continue...");
|
|
getchar();
|
|
}
|
|
|
|
CoUninitialize();
|
|
return rc;
|
|
}
|