zen::Xml
Simple C++ XML Processing
 All Classes Namespaces Functions Variables
io.h
00001 // **************************************************************************
00002 // * This file is part of the zen::Xml project. It is distributed under the *
00003 // * Boost Software License: http://www.boost.org/LICENSE_1_0.txt           *
00004 // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved        *
00005 // **************************************************************************
00006 
00007 #ifndef ZEN_XML_IO_HEADER_8917640501480763248343343
00008 #define ZEN_XML_IO_HEADER_8917640501480763248343343
00009 
00010 #include <cstdio>
00011 #include <cerrno>
00012 #include <zen/scope_guard.h>
00013 #include <zen/utf.h>
00014 #include "error.h"
00015 
00016 namespace zen
00017 {
00023 #if !defined(ZEN_PLATFORM_WINDOWS) && !defined(ZEN_PLATFORM_OTHER)
00024 #error Please specify your platform: #define ZEN_PLATFORM_WINDOWS or ZEN_PLATFORM_OTHER
00025 #endif
00026 
00028 struct XmlFileError : public XmlError
00029 {
00030     typedef int ErrorCode;
00031 
00032     explicit XmlFileError(ErrorCode ec) : lastError(ec) {}
00034     ErrorCode lastError;
00035 };
00036 
00037 
00038 #ifdef ZEN_PLATFORM_WINDOWS
00039 namespace implemenation //sad but true
00040 {
00041 template <class String> inline
00042 FILE* fopen(const String& filename, const wchar_t* mode)
00043 {
00044 #ifdef _MSC_VER
00045     FILE* handle = nullptr;
00046     errno_t rv = ::_wfopen_s(&handle, utfCvrtTo<std::wstring>(filename).c_str(), mode); //more secure?
00047     (void)rv;
00048     return handle;
00049 #else
00050     return ::_wfopen(utfCvrtTo<std::wstring>(filename).c_str(), mode);
00051 #endif
00052 }
00053 }
00054 #endif
00055 
00056 
00058 
00064 template <class String>
00065 void saveStream(const std::string& stream, const String& filename) //throw XmlFileError
00066 {
00067 #ifdef ZEN_PLATFORM_WINDOWS
00068     FILE* handle = implemenation::fopen(utfCvrtTo<std::wstring>(filename).c_str(), L"wb");
00069 #else
00070     FILE* handle = ::fopen(utfCvrtTo<std::string>(filename).c_str(), "w");
00071 #endif
00072     if (handle == nullptr)
00073         throw XmlFileError(errno);
00074     ZEN_ON_SCOPE_EXIT(::fclose(handle));
00075 
00076     const size_t bytesWritten = ::fwrite(stream.c_str(), 1, stream.size(), handle);
00077     if (::ferror(handle) != 0)
00078         throw XmlFileError(errno);
00079 
00080     (void)bytesWritten;
00081     assert(bytesWritten == stream.size());
00082 }
00083 
00084 
00086 
00092 template <class String>
00093 std::string loadStream(const String& filename) //throw XmlFileError
00094 {
00095 #ifdef ZEN_PLATFORM_WINDOWS
00096     FILE* handle = implemenation::fopen(utfCvrtTo<std::wstring>(filename).c_str(), L"rb");
00097 #else
00098     FILE* handle = ::fopen(utfCvrtTo<std::string>(filename).c_str(), "r");
00099 #endif
00100     if (handle == nullptr)
00101         throw XmlFileError(errno);
00102     ZEN_ON_SCOPE_EXIT(::fclose(handle));
00103 
00104     std::string stream;
00105     const size_t blockSize = 64 * 1024;
00106     do
00107     {
00108         stream.resize(stream.size() + blockSize); //let's pray std::string implements exponential growth!
00109 
00110         const size_t bytesRead = ::fread(&*(stream.begin() + stream.size() - blockSize), 1, blockSize, handle);
00111         if (::ferror(handle))
00112             throw XmlFileError(errno);
00113         if (bytesRead > blockSize)
00114             throw XmlFileError(0);
00115         if (bytesRead < blockSize)
00116             stream.resize(stream.size() - (blockSize - bytesRead)); //caveat: unsigned arithmetics
00117     }
00118     while (!::feof(handle));
00119 
00120     return stream;
00121 }
00122 }
00123 
00124 #endif //ZEN_XML_IO_HEADER_8917640501480763248343343