#include #include #include #include #include #include "xml_article.h" using namespace std; void SaveWideBufferToFileUTF8(HANDLE hFile, LPCWSTR pwch, int cch) { //Guess the size of contents in UTF-8 encoding is less than 120% of characters in Unicode. //This guess is usually correct, and is therefore faster than asking, allocating and converting. 06/18/01 BB int nBuffer(cch*6/5); //NOTE: Six-fifths == 120% //Convert bstrContents to UTF-8. auto_ptr pBuffer(new char[nBuffer]); if (0 == (nBuffer = WideCharToMultiByte(CP_UTF8,0, pwch, cch, pBuffer.get(), nBuffer, NULL, NULL))) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) throw runtime_error("Couldn't convert to UTF-8."); //Buffer size guess was wrong; take the time to ask API to give us the exact size. nBuffer = WideCharToMultiByte(CP_UTF8,0,pwch, cch, NULL, 0, NULL, NULL); delete [] pBuffer.release(); pBuffer = auto_ptr(new char[nBuffer]); if (!WideCharToMultiByte(CP_UTF8,0,pwch, cch, pBuffer.get(), nBuffer, NULL, NULL)) throw runtime_error("Couldn't convert to UTF-8."); } DWORD dwNumBytesWritten; //Write pBuffer to the file. if( !WriteFile( hFile, pBuffer.get(), nBuffer, &dwNumBytesWritten, NULL ) ) throw runtime_error("Couldn't write file."); } IFileStream::IFileStream(LPCWSTR szFile): m_refCnt(0) { m_hFile = CreateFileW( szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if( m_hFile == INVALID_HANDLE_VALUE ) throw std::logic_error("Could not open file."); AddRef(); } IFileStream::~IFileStream() { CloseHandle(m_hFile); } STDMETHODIMP IFileStream::Write(const void __RPC_FAR *pv,ULONG cb, ULONG __RPC_FAR *pcbWritten) { SaveWideBufferToFileUTF8(m_hFile, (LPCWSTR) pv, cb/2); *pcbWritten = cb; return S_OK; } long __stdcall IFileStream::QueryInterface(const struct _GUID &riid,void ** ppvObject) { *ppvObject = NULL; if (riid == IID_IUnknown ||riid == __uuidof(IStream)) { *ppvObject = static_cast(this); AddRef(); return S_OK; } return E_NOINTERFACE; } unsigned long __stdcall IFileStream::AddRef() { return ++m_refCnt; // NOT thread-safe } unsigned long __stdcall IFileStream::Release() { --m_refCnt; // NOT thread-safe if (m_refCnt == 0) { delete this; return 0; // Can't return the member of a deleted object. } else return m_refCnt; } //NOTE: MXFileWriter is derived from IMXWriterPtr, so an instance of //this class can be used in place of a standard IMXWriterPtr. //The difference is, all output will be saved to the file specified //in the constructor, or in the SetFileLocation method. MXFileWriter::MXFileWriter(LPCWSTR szFile) : m_pFileStream(NULL) { CreateInstance(__uuidof(MSXML2::MXXMLWriter)); if (szFile) SetFileLocation(szFile); } MXFileWriter::~MXFileWriter() { if (m_pFileStream) m_pFileStream->Release(); //self-deleting on zero reference count } //Start writing to a new file. MXFileWriter::SetFileLocation(LPCWSTR szFile) { if (m_pFileStream) m_pFileStream->Release(); //self-deleting on zero reference count m_pFileStream = NULL; m_pFileStream = new IFileStream(szFile); //Here's the $64,000 Line: Redirect output as a variant containing an IStream pointer. GetInterfacePtr()->put_output(_variant_t((IStream *)m_pFileStream)); }