// ************************************************************************** // * This file is part of the zenXML project. It is distributed under the * // * Boost Software License: http://www.boost.org/LICENSE_1_0.txt * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef ZEN_XML_IO_HEADER_8917640501480763248343343 #define ZEN_XML_IO_HEADER_8917640501480763248343343 #include #include #include #include #include "error.h" namespace zen { /** \file \brief Save and load byte streams from files */ #if !defined(ZEN_PLATFORM_WINDOWS) && !defined(ZEN_PLATFORM_OTHER) #error Please specify your platform: #define ZEN_PLATFORM_WINDOWS or ZEN_PLATFORM_OTHER #endif ///Exception thrown due to failed file I/O struct XmlFileError : public XmlError { typedef int ErrorCode; explicit XmlFileError(ErrorCode ec) : lastError(ec) {} ///Native error code: errno ErrorCode lastError; }; #ifdef ZEN_PLATFORM_WINDOWS namespace implemenation //sad but true { template inline FILE* fopen(const String& filename, const wchar_t* mode) { #ifdef _MSC_VER FILE* handle = nullptr; errno_t rv = ::_wfopen_s(&handle, utfCvrtTo(filename).c_str(), mode); //more secure? (void)rv; return handle; #else return ::_wfopen(utfCvrtTo(filename).c_str(), mode); #endif } } #endif ///Save byte stream to a file /** \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... \param stream Input byte stream \param filename Output file name \throw XmlFileError */ template void saveStream(const std::string& stream, const String& filename) //throw XmlFileError { #ifdef ZEN_PLATFORM_WINDOWS FILE* handle = implemenation::fopen(utfCvrtTo(filename).c_str(), L"wb"); #else FILE* handle = ::fopen(utfCvrtTo(filename).c_str(), "w"); #endif if (handle == nullptr) throw XmlFileError(errno); ZEN_ON_SCOPE_EXIT(::fclose(handle)); const size_t bytesWritten = ::fwrite(stream.c_str(), 1, stream.size(), handle); if (::ferror(handle) != 0) throw XmlFileError(errno); (void)bytesWritten; assert(bytesWritten == stream.size()); } ///Load byte stream from a file /** \tparam String Arbitrary string-like type: e.g. std::string, wchar_t*, char[], wchar_t, wxString, MyStringClass, ... \param filename Input file name \return Output byte stream \throw XmlFileError */ template std::string loadStream(const String& filename) //throw XmlFileError { #ifdef ZEN_PLATFORM_WINDOWS FILE* handle = implemenation::fopen(utfCvrtTo(filename).c_str(), L"rb"); #else FILE* handle = ::fopen(utfCvrtTo(filename).c_str(), "r"); #endif if (handle == nullptr) throw XmlFileError(errno); ZEN_ON_SCOPE_EXIT(::fclose(handle)); std::string stream; const size_t blockSize = 64 * 1024; do { stream.resize(stream.size() + blockSize); //let's pray std::string implements exponential growth! const size_t bytesRead = ::fread(&*(stream.begin() + stream.size() - blockSize), 1, blockSize, handle); if (::ferror(handle)) throw XmlFileError(errno); if (bytesRead > blockSize) throw XmlFileError(0); if (bytesRead < blockSize) stream.resize(stream.size() - (blockSize - bytesRead)); //caveat: unsigned arithmetics } while (!::feof(handle)); return stream; } } #endif //ZEN_XML_IO_HEADER_8917640501480763248343343