//----------------------------------------------------------------------- // This file is part of the Windows SDK Code Samples. // // Copyright (C) Microsoft Corporation. All rights reserved. // // This source code is intended only as a supplement to Microsoft // Development Tools and/or on-line documentation. See these other // materials for detailed information regarding Microsoft code samples. // // THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. //----------------------------------------------------------------------- #include "stdafx.h" #include #include "xmllite.h" #include //implement filestream that derives from IStream class FileStream : public IStream { FileStream(HANDLE hFile) { _refcount = 1; _hFile = hFile; } ~FileStream() { if (_hFile != INVALID_HANDLE_VALUE) { ::CloseHandle(_hFile); } } public: HRESULT static OpenFile(LPCWSTR pName, IStream ** ppStream, bool fWrite) { HANDLE hFile = ::CreateFileW(pName, fWrite ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, NULL, fWrite ? CREATE_ALWAYS : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(GetLastError()); *ppStream = new FileStream(hFile); if(*ppStream == NULL) CloseHandle(hFile); return S_OK; } virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject) { if (iid == __uuidof(IUnknown) || iid == __uuidof(IStream) || iid == __uuidof(ISequentialStream)) { *ppvObject = static_cast(this); AddRef(); return S_OK; } else return E_NOINTERFACE; } virtual ULONG STDMETHODCALLTYPE AddRef(void) { return (ULONG)InterlockedIncrement(&_refcount); } virtual ULONG STDMETHODCALLTYPE Release(void) { ULONG res = (ULONG) InterlockedDecrement(&_refcount); if (res == 0) delete this; return res; } // ISequentialStream Interface public: virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead) { BOOL rc = ReadFile(_hFile, pv, cb, pcbRead, NULL); return (rc) ? S_OK : HRESULT_FROM_WIN32(GetLastError()); } virtual HRESULT STDMETHODCALLTYPE Write(void const* pv, ULONG cb, ULONG* pcbWritten) { BOOL rc = WriteFile(_hFile, pv, cb, pcbWritten, NULL); return rc ? S_OK : HRESULT_FROM_WIN32(GetLastError()); } // IStream Interface public: virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream*, ULARGE_INTEGER, ULARGE_INTEGER*, ULARGE_INTEGER*) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE Commit(DWORD) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE Revert(void) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE Clone(IStream **) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove, DWORD dwOrigin, ULARGE_INTEGER* lpNewFilePointer) { DWORD dwMoveMethod; switch(dwOrigin) { case STREAM_SEEK_SET: dwMoveMethod = FILE_BEGIN; break; case STREAM_SEEK_CUR: dwMoveMethod = FILE_CURRENT; break; case STREAM_SEEK_END: dwMoveMethod = FILE_END; break; default: return STG_E_INVALIDFUNCTION; break; } if (SetFilePointerEx(_hFile, liDistanceToMove, (PLARGE_INTEGER) lpNewFilePointer, dwMoveMethod) == 0) return HRESULT_FROM_WIN32(GetLastError()); return S_OK; } virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg, DWORD grfStatFlag) { if (GetFileSizeEx(_hFile, (PLARGE_INTEGER) &pStatstg->cbSize) == 0) return HRESULT_FROM_WIN32(GetLastError()); return S_OK; } private: HANDLE _hFile; LONG _refcount; }; int _tmain(int argc, WCHAR* argv[]) { HRESULT hr; CComPtr pFileStream; CComPtr pOutFileStream; CComPtr pReader; CComPtr pWriter; CComPtr pReaderInput; CComPtr pWriterOutput; if (argc != 3) { wprintf( L"Usage: XmlReaderWriter.exe name-of-input-file name-of-output-file\n"); return 0; } //Open read-only input stream if (FAILED(hr = FileStream::OpenFile(argv[1], &pFileStream, FALSE))) { wprintf(L"Error creating file reader, error is %08.8lx", hr); return -1; } //Open writeable output stream if (FAILED(hr = FileStream::OpenFile(argv[2], &pOutFileStream, TRUE))) { wprintf(L"Error creating file writer, error is %08.8lx", hr); return -1; } if (FAILED(hr = CreateXmlReader(__uuidof(IXmlReader), (void**) &pReader, NULL))) { wprintf(L"Error creating xml reader, error is %08.8lx", hr); return -1; } pReader->SetProperty(XmlReaderProperty_DtdProcessing, DtdProcessing_Prohibit); if (FAILED(hr = CreateXmlReaderInputWithEncodingCodePage(pFileStream, NULL, 65001, FALSE, L"c:\temp", &pReaderInput))) { wprintf(L"Error creating xml reader with encoding code page, error is %08.8lx", hr); return -1; } if (FAILED(hr = CreateXmlWriter(__uuidof(IXmlWriter),(void**) &pWriter, NULL))) { wprintf(L"Error creating xml writer, error is %08.8lx", hr); return -1; } if (FAILED(hr = CreateXmlWriterOutputWithEncodingCodePage(pOutFileStream, NULL, 65001, &pWriterOutput))) { wprintf(L"Error creating xml reader with encoding code page, error is %08.8lx", hr); return -1; } if (FAILED(hr = pReader->SetInput(pReaderInput))) { wprintf(L"Error setting input for reader, error is %08.8lx", hr); return -1; } if (FAILED(hr = pWriter->SetOutput(pWriterOutput))) { wprintf(L"Error setting output for writer, error is %08.8lx", hr); return -1; } if (FAILED(hr = pWriter->SetProperty(XmlWriterProperty_Indent, TRUE))) { wprintf(L"Error setting indent property in writer, error is %08.8lx", hr); return -1; } XmlNodeType nodeType; const WCHAR* pQName; const WCHAR* pValue; double originalPrice = 0.0; double newPrice = 0.0; WCHAR priceString[100]; bool inPrice = FALSE; /* * This quick start reads an XML of the form * * * price-of-book1 * * * price-of-book2 * * * * and applies a 25% discount to the price of the book. It also adds originalPrice and discount * as two attributes to the element price. If the price is empty or an empty element, it does * not make any changes. So the transformed XML will be: * * * * * discounted-price-of-book1 * * * * * discounted-price-of-book2 * * * * */ //read until there are no more nodes while (S_OK == (hr = pReader->Read(&nodeType))) { // WriteNode will move the reader to the next node, so inside the While Read loop, it is // essential that we use WriteNodeShallow, which will not move the reader. // If not, a node will be skipped every time you use WriteNode in the while loop. switch (nodeType) { case XmlNodeType_Element: { if (pReader->IsEmptyElement()) { if (FAILED(hr = pWriter->WriteNodeShallow(pReader, FALSE))) { wprintf(L"Error writing WriteNodeShallow, error is %08.8lx", hr); return -1; } } else { // if you are not interested in the length it may be faster to use // NULL for the length parameter if (FAILED(hr = pReader->GetQualifiedName(&pQName, NULL))) { wprintf(L"Error reading element name, error is %08.8lx", hr); return -1; } //if the element is price, then discount price by 25% if (wcscmp(pQName, L"price") == 0) { inPrice = TRUE; if (FAILED(hr = pWriter->WriteNodeShallow(pReader, FALSE))) { wprintf(L"Error writing WriteNodeShallow, error is %08.8lx", hr); return -1; } } else { inPrice = FALSE; if (FAILED(hr = pWriter->WriteNodeShallow(pReader, FALSE))) { wprintf(L"Error writing WriteNodeShallow, error is %08.8lx", hr); return -1; } } } } break; case XmlNodeType_Text: if (inPrice == TRUE) { if (FAILED(hr = pReader->GetValue(&pValue, NULL))) { wprintf(L"Error reading value, error is %08.8lx", hr); return -1; } //apply discount to the node originalPrice = _wtof(pValue); newPrice = originalPrice * 0.75; if (FAILED(hr = StringCbPrintfW(priceString, sizeof (priceString), L"%f", newPrice))) { wprintf(L"Error using StringCchPrintfW, error is %08.8lx", hr); return -1; } //write attributes if any if (FAILED(hr = pWriter->WriteAttributeString(NULL, L"originalPrice", NULL, pValue))) { wprintf(L"Error writing WriteAttributeString, error is %08.8lx", hr); return -1; } if (FAILED(hr = pWriter->WriteAttributeString(NULL, L"discount", NULL, L"25%"))) { wprintf(L"Error writing WriteAttributeString, error is %08.8lx", hr); return -1; } if (FAILED(hr = pWriter->WriteString(priceString))) { wprintf(L"Error writing WriteString, error is %08.8lx", hr); return -1; } inPrice = FALSE; } else { if (FAILED(hr = pWriter->WriteNodeShallow(pReader, FALSE))) { wprintf(L"Error writing WriteNodeShallow, error is %08.8lx", hr); return -1; } } break; case XmlNodeType_EndElement: if (FAILED(hr = pReader->GetQualifiedName(&pQName, NULL))) { wprintf(L"Error reading element name, error is %08.8lx", hr); return -1; } if (wcscmp(pQName, L"price") == 0) //if the end element is price, then reset inPrice inPrice = FALSE; if (FAILED(hr = pWriter->WriteFullEndElement())) { wprintf(L"Error writing WriteFullEndElement, error is %08.8lx", hr); return -1; } break; default: { if (FAILED(hr = pWriter->WriteNodeShallow(pReader, FALSE))) { wprintf(L"Error writing WriteNodeShallow, error is %08.8lx", hr); return -1; } } break; } } return 0; }