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.
518 lines
16 KiB
518 lines
16 KiB
#include "nt.h"
|
|
#include "ntdef.h"
|
|
#include "ntrtl.h"
|
|
#include "nturtl.h"
|
|
#include "fci.h"
|
|
#include "stdio.h"
|
|
#include "sxs-rtl.h"
|
|
#include "fasterxml.h"
|
|
#include "skiplist.h"
|
|
#include "namespacemanager.h"
|
|
#include "xmlstructure.h"
|
|
|
|
#ifdef INVALID_HANDLE_VALUE
|
|
#undef INVALID_HANDLE_VALUE
|
|
#endif
|
|
#include "windows.h"
|
|
#include "stdlib.h"
|
|
|
|
NTSTATUS FASTCALL
|
|
MyAllocator(SIZE_T cb, PVOID* pvOutput, PVOID pvAllocContext) {
|
|
ASSERT(pvAllocContext == NULL);
|
|
*pvOutput = RtlAllocateHeap(RtlProcessHeap(), 0, cb);
|
|
return *pvOutput ? STATUS_SUCCESS : STATUS_NO_MEMORY;
|
|
}
|
|
|
|
NTSTATUS FASTCALL
|
|
MyFreer(PVOID pv, PVOID pvAllocContext) {
|
|
ASSERT(pvAllocContext == NULL);
|
|
return RtlFreeHeap(RtlProcessHeap(), 0, pv) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
EXTERN_C RTL_ALLOCATOR g_DefaultAllocator = {MyAllocator, MyFreer, NULL};
|
|
|
|
|
|
void GetFormattedStateName(
|
|
XML_TOKENIZATION_SPECIFIC_STATE State,
|
|
CHAR *rgszBuffer,
|
|
SIZE_T cchBuffer
|
|
)
|
|
{
|
|
CHAR *pszSpecific = NULL;
|
|
SIZE_T cchSpecific = 0;
|
|
|
|
#define STRINGIFY(str, sz, cch) case str: sz = #str; cch = NUMBER_OF(#str) - 1; break
|
|
|
|
switch(State) {
|
|
STRINGIFY(XTSS_ERRONEOUS, pszSpecific, cchSpecific);
|
|
|
|
STRINGIFY(XTSS_ELEMENT_OPEN, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_NAME, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_CLOSE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_CLOSE_EMPTY, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_ATTRIBUTE_NAME, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_ATTRIBUTE_EQUALS, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_ATTRIBUTE_OPEN, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_ATTRIBUTE_CLOSE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_ATTRIBUTE_VALUE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_WHITESPACE, pszSpecific, cchSpecific);
|
|
|
|
STRINGIFY(XTSS_ELEMENT_XMLNS, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_XMLNS_DEFAULT, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_XMLNS_ALIAS, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_XMLNS_COLON, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_XMLNS_EQUALS, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_XMLNS_VALUE_OPEN, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_XMLNS_VALUE_CLOSE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_XMLNS_VALUE, pszSpecific, cchSpecific);
|
|
|
|
STRINGIFY(XTSS_ELEMENT_NAME_NS_PREFIX, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_NAME_NS_COLON, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_ATTRIBUTE_NAME_NS_PREFIX, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ELEMENT_ATTRIBUTE_NAME_NS_COLON, pszSpecific, cchSpecific);
|
|
|
|
STRINGIFY(XTSS_ENDELEMENT_OPEN, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ENDELEMENT_NAME, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ENDELEMENT_WHITESPACE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_ENDELEMENT_CLOSE, pszSpecific, cchSpecific);
|
|
|
|
STRINGIFY(XTSS_XMLDECL_OPEN, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_XMLDECL_CLOSE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_XMLDECL_WHITESPACE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_XMLDECL_VALUE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_XMLDECL_VALUE_OPEN, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_XMLDECL_VALUE_CLOSE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_XMLDECL_EQUALS, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_XMLDECL_ENCODING, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_XMLDECL_STANDALONE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_XMLDECL_VERSION, pszSpecific, cchSpecific);
|
|
|
|
STRINGIFY(XTSS_PI_OPEN, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_PI_CLOSE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_PI_TARGET, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_PI_VALUE, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_PI_WHITESPACE, pszSpecific, cchSpecific);
|
|
|
|
STRINGIFY(XTSS_CDATA_OPEN, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_CDATA_CDATA, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_CDATA_CLOSE, pszSpecific, cchSpecific);
|
|
|
|
STRINGIFY(XTSS_COMMENT_OPEN, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_COMMENT_COMMENTARY, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_COMMENT_CLOSE, pszSpecific, cchSpecific);
|
|
|
|
STRINGIFY(XTSS_STREAM_START, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_STREAM_END, pszSpecific, cchSpecific);
|
|
STRINGIFY(XTSS_STREAM_HYPERSPACE, pszSpecific, cchSpecific);
|
|
|
|
default:
|
|
pszSpecific = "bad specific state"; cchSpecific = strlen(pszSpecific);
|
|
break;
|
|
}
|
|
|
|
_snprintf(rgszBuffer, cchBuffer, "%s", pszSpecific);
|
|
}
|
|
|
|
void DisplayToken(PXML_TOKEN pToken, FILE* pFile)
|
|
{
|
|
static char Formatter[4096];
|
|
SIZE_T i;
|
|
|
|
GetFormattedStateName(pToken->State, Formatter, NUMBER_OF(Formatter));
|
|
fprintf(pFile, "%s, %d {%.*s}\n",
|
|
Formatter,
|
|
pToken->Run.cbData,
|
|
pToken->Run.cbData,
|
|
pToken->Run.pvData);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
DisplayLogicalThing(
|
|
PXMLDOC_THING pThing,
|
|
PRTL_GROWING_LIST pAttributeList
|
|
)
|
|
{
|
|
printf("Extent {0x%p, %d} (depth %d):\n",
|
|
pThing->TotalExtent.pvData,
|
|
pThing->TotalExtent.cbData,
|
|
pThing->ulDocumentDepth);
|
|
|
|
switch (pThing->ulThingType) {
|
|
case XMLDOC_THING_HYPERSPACE:
|
|
{
|
|
printf("\tHyperspace: {%.*s}\n", pThing->Hyperspace.cbData, pThing->Hyperspace.pvData);
|
|
}
|
|
break;
|
|
|
|
case XMLDOC_THING_ELEMENT:
|
|
{
|
|
PXMLDOC_ATTRIBUTE pAttribute = NULL;
|
|
ULONG ul = 0;
|
|
NTSTATUS status;
|
|
|
|
printf("\tElement {%.*s:%.*s} %d attributes %s\n",
|
|
pThing->Element.NsPrefix.cbData,
|
|
pThing->Element.NsPrefix.pvData,
|
|
pThing->Element.Name.cbData,
|
|
pThing->Element.Name.pvData,
|
|
pThing->Element.ulAttributeCount,
|
|
(pThing->Element.fElementEmpty ? "(empty)" : ""));
|
|
|
|
for (ul = 0; ul < pThing->Element.ulAttributeCount; ul++) {
|
|
|
|
status = RtlIndexIntoGrowingList(
|
|
pAttributeList,
|
|
ul,
|
|
(PVOID*)&pAttribute,
|
|
FALSE);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
printf("\t\tAttribute {%.*s:%.*s}={%.*s}\n",
|
|
pAttribute->NsPrefix.cbData,
|
|
pAttribute->NsPrefix.pvData,
|
|
pAttribute->Name.cbData,
|
|
pAttribute->Name.pvData,
|
|
pAttribute->Value.cbData,
|
|
pAttribute->Value.pvData);
|
|
}
|
|
else {
|
|
printf("\t\t(Can't get attribute, error 0x%08lx)\n", status);
|
|
}
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case XMLDOC_THING_XMLDECL:
|
|
{
|
|
PXMLDOC_XMLDECL pDecl = &pThing->XmlDecl;
|
|
printf("\tXML Declaration: encoding {%.*s} version {%.*s} standalone {%.*s}\n",
|
|
pDecl->Encoding.cbData,
|
|
pDecl->Encoding.pvData,
|
|
pDecl->Version.cbData,
|
|
pDecl->Version.pvData,
|
|
pDecl->Standalone.cbData,
|
|
pDecl->Standalone.pvData);
|
|
}
|
|
break;
|
|
|
|
case XMLDOC_THING_END_ELEMENT:
|
|
{
|
|
PXMLDOC_ENDELEMENT pElement = &pThing->EndElement;
|
|
|
|
printf("\tClosing element {%.*s:%.*s} for tag {%.*s:%.*s}\n",
|
|
pElement->NsPrefix.cbData,
|
|
pElement->NsPrefix.pvData,
|
|
pElement->Name.cbData,
|
|
pElement->Name.pvData,
|
|
pElement->OpeningElement.NsPrefix.cbData,
|
|
pElement->OpeningElement.NsPrefix.pvData,
|
|
pElement->OpeningElement.Name.cbData,
|
|
pElement->OpeningElement.Name.pvData);
|
|
}
|
|
break;
|
|
|
|
case XMLDOC_THING_END_OF_STREAM:
|
|
printf("End of stream\n");
|
|
break;
|
|
|
|
case XMLDOC_THING_ERROR:
|
|
{
|
|
PXMLDOC_ERROR pError = &pThing->Error;
|
|
|
|
printf("\tError in XML (or parser) found at {%.*s}, code %08lx\n",
|
|
pError->BadExtent.cbData,
|
|
pError->BadExtent.pvData,
|
|
pError->Code);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
BOOL s_fDisplay = FALSE;
|
|
|
|
|
|
NTSTATUS
|
|
RunThroughFile(
|
|
PVOID pvData,
|
|
SIZE_T cbData
|
|
)
|
|
{
|
|
XML_LOGICAL_STATE MasterParseState;
|
|
XMLDOC_THING DocumentPiece;
|
|
RTL_GROWING_LIST AttributeList;
|
|
NTSTATUS status;
|
|
LARGE_INTEGER liStart, liEnd;
|
|
|
|
QueryPerformanceCounter(&liStart);
|
|
|
|
status = RtlInitializeGrowingList(
|
|
&AttributeList,
|
|
sizeof(XMLDOC_ATTRIBUTE),
|
|
20,
|
|
NULL,
|
|
0,
|
|
&g_DefaultAllocator);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
status = RtlXmlInitializeNextLogicalThing(
|
|
&MasterParseState,
|
|
pvData,
|
|
cbData,
|
|
&g_DefaultAllocator);
|
|
|
|
while (NT_SUCCESS(status)) {
|
|
|
|
status = RtlXmlNextLogicalThing(
|
|
&MasterParseState,
|
|
NULL,
|
|
&DocumentPiece,
|
|
&AttributeList);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
if (s_fDisplay)
|
|
DisplayLogicalThing(&DocumentPiece, &AttributeList);
|
|
|
|
if ((DocumentPiece.ulThingType == XMLDOC_THING_ERROR) ||
|
|
(DocumentPiece.ulThingType == XMLDOC_THING_END_OF_STREAM)) {
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
QueryPerformanceCounter(&liEnd);
|
|
|
|
liEnd.QuadPart -= liStart.QuadPart;
|
|
QueryPerformanceFrequency(&liStart);
|
|
|
|
printf("%I64d ticks, %f seconds\n", liEnd.QuadPart, (double)liEnd.QuadPart / (double)liStart.QuadPart);
|
|
|
|
if (DocumentPiece.ulThingType == XMLDOC_THING_END_OF_STREAM) {
|
|
|
|
if (DocumentPiece.ulDocumentDepth == 0) {
|
|
printf("Completed input stream\n");
|
|
}
|
|
else {
|
|
printf("EOF before end of stream, %d elements on stack.\n",
|
|
DocumentPiece.ulDocumentDepth);
|
|
}
|
|
}
|
|
else {
|
|
printf("Error found in stream processing at %.*s, byte offset %d.\n",
|
|
DocumentPiece.TotalExtent.cbData,
|
|
DocumentPiece.TotalExtent.pvData,
|
|
(PBYTE)DocumentPiece.TotalExtent.pvData - (PBYTE)pvData
|
|
);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
TimeFileRun(
|
|
PVOID pvFileData,
|
|
SIZE_T dwFileSize,
|
|
PLARGE_INTEGER pliTickCount,
|
|
double* pdblSecondCount)
|
|
{
|
|
XML_LOGICAL_STATE State;
|
|
XML_TOKEN Token;
|
|
LARGE_INTEGER liStartTime, liEndTime;
|
|
SIZE_T ulEncodingBytes;
|
|
NTSTATUS success;
|
|
|
|
//
|
|
// Start up the parser
|
|
//
|
|
success = RtlXmlInitializeTokenization(&State.ParseState, pvFileData, dwFileSize, NULL, NULL, NULL);
|
|
if (!NT_SUCCESS(success)) {
|
|
printf("Initialization failure\n");
|
|
}
|
|
|
|
State.ulElementStackDepth = 0;
|
|
success = RtlInitializeGrowingList(
|
|
&State.ElementStack,
|
|
sizeof(XMLDOC_THING),
|
|
40,
|
|
State.InlineElements,
|
|
sizeof(State.InlineElements),
|
|
&g_DefaultAllocator);
|
|
|
|
if (!NT_SUCCESS(success)) {
|
|
printf("Unable to create element stack");
|
|
return success;
|
|
}
|
|
|
|
//
|
|
// Let's determine the encoding
|
|
//
|
|
success = RtlXmlDetermineStreamEncoding(&State.ParseState, &ulEncodingBytes, &State.EncodingMarker);
|
|
if (!NT_SUCCESS(success)) {
|
|
printf("Unable to determine the encoding type\n");
|
|
}
|
|
|
|
//
|
|
// Advance cursor past encoding bytes if necessary
|
|
//
|
|
State.ParseState.RawTokenState.pvCursor = ((PBYTE)State.ParseState.RawTokenState.pvCursor) + ulEncodingBytes;
|
|
|
|
QueryPerformanceCounter(&liStartTime);
|
|
do
|
|
{
|
|
|
|
if (NT_SUCCESS(success = RtlXmlNextToken(&State.ParseState, &Token, TRUE))) {
|
|
|
|
//
|
|
// Was there an error in this token?
|
|
//
|
|
if (s_fDisplay)
|
|
DisplayToken(&Token, stdout);
|
|
|
|
if (Token.fError) {
|
|
printf("(Which was considered an error)\n");
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
while (NT_SUCCESS(success) && !Token.fError && (Token.State != XTSS_STREAM_END));
|
|
|
|
QueryPerformanceCounter(&liEndTime);
|
|
|
|
pliTickCount->QuadPart = liEndTime.QuadPart - liStartTime.QuadPart;
|
|
|
|
QueryPerformanceFrequency(&liStartTime);
|
|
|
|
*pdblSecondCount = (double)pliTickCount->QuadPart / liStartTime.QuadPart;
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
DWORD WARMUP_COUNT = 3;
|
|
DWORD REAL_COUNT = 5;
|
|
|
|
int __cdecl wmain(int argc, WCHAR* argv[])
|
|
{
|
|
NTSTATUS success = STATUS_SUCCESS;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
HANDLE hFileMapping = INVALID_HANDLE_VALUE;
|
|
PVOID pvFileData = NULL;
|
|
DWORD dwFileSize = 0;
|
|
BOOL fFirstElementFound = FALSE;
|
|
LARGE_INTEGER liTickCount, liTotalTicks;
|
|
double dblSeconds, dblTotalSeconds;
|
|
PCWSTR pcwszFileName = NULL;
|
|
DWORD dw = 0;
|
|
|
|
BOOL fJustRun = FALSE;
|
|
int i;
|
|
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (lstrcmpiW(L"-file", argv[i]) == 0) {
|
|
pcwszFileName = argv[++i];
|
|
}
|
|
else if (lstrcmpiW(L"-warmup", argv[i]) == 0) {
|
|
WARMUP_COUNT = _wtoi(argv[++i]);
|
|
}
|
|
else if (lstrcmpiW(L"-real", argv[i]) == 0) {
|
|
REAL_COUNT = _wtoi(argv[++i]);
|
|
}
|
|
else if (lstrcmpiW(L"-display", argv[i]) == 0) {
|
|
s_fDisplay = TRUE;
|
|
}
|
|
}
|
|
|
|
if (pcwszFileName == NULL)
|
|
{
|
|
wprintf(L"Must specify at least '-file somefile'\r\n");
|
|
return -1;
|
|
}
|
|
|
|
hFile = CreateFileW(
|
|
pcwszFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
printf("Can't open file %ls\n", pcwszFileName);
|
|
return -1;
|
|
}
|
|
|
|
dwFileSize = GetFileSize(hFile, NULL);
|
|
|
|
hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileSize, NULL);
|
|
if ((hFileMapping == NULL) || (hFileMapping == INVALID_HANDLE_VALUE)) {
|
|
CloseHandle(hFile);
|
|
wprintf(L"Can't create file mapping of %ls, lasterror %d\n", pcwszFileName, GetLastError());
|
|
return -1;
|
|
}
|
|
|
|
pvFileData = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, dwFileSize);
|
|
if (pvFileData == NULL) {
|
|
CloseHandle(hFile);
|
|
CloseHandle(hFileMapping);
|
|
wprintf(L"Can't create mapped view of file %ls\n", pcwszFileName);
|
|
return -1;
|
|
}
|
|
|
|
for (dw = 0; dw < WARMUP_COUNT; dw++) {
|
|
wprintf(L"Warmup cycle %d\n", dw);
|
|
success = TimeFileRun(pvFileData, dwFileSize, &liTickCount, &dblSeconds);
|
|
wprintf(L"%I64d ticks, %f seconds\n", liTickCount.QuadPart, dblSeconds);
|
|
}
|
|
|
|
wprintf(L"This one counts:\n");
|
|
|
|
liTotalTicks.QuadPart = 0;
|
|
dblTotalSeconds = 0.0;
|
|
|
|
for (dw = 0; dw < REAL_COUNT; dw++) {
|
|
success = TimeFileRun(pvFileData, dwFileSize, &liTickCount, &dblSeconds);
|
|
dblTotalSeconds += dblSeconds;
|
|
liTotalTicks.QuadPart += liTickCount.QuadPart;
|
|
wprintf(L".");
|
|
}
|
|
|
|
wprintf(L"\n");
|
|
|
|
if (REAL_COUNT == 0)
|
|
{
|
|
wprintf(L"No real runs, can't calculate time.\n");
|
|
}
|
|
else {
|
|
wprintf(L"%d runs: %I64d total ticks, %I64d average, %f total seconds, %f average\n",
|
|
REAL_COUNT,
|
|
liTotalTicks.QuadPart,
|
|
liTotalTicks.QuadPart / REAL_COUNT,
|
|
dblTotalSeconds,
|
|
dblTotalSeconds / REAL_COUNT);
|
|
}
|
|
|
|
success = RunThroughFile(pvFileData, dwFileSize);
|
|
|
|
CloseHandle(hFile);
|
|
CloseHandle(hFileMapping);
|
|
UnmapViewOfFile(pvFileData);
|
|
|
|
return success;
|
|
success = RtlInstallAssembly(0, argv[1]);
|
|
}
|