summaryrefslogtreecommitdiff
path: root/zenxml/io.h
diff options
context:
space:
mode:
Diffstat (limited to 'zenxml/io.h')
-rw-r--r--zenxml/io.h124
1 files changed, 124 insertions, 0 deletions
diff --git a/zenxml/io.h b/zenxml/io.h
new file mode 100644
index 00000000..4286ae6c
--- /dev/null
+++ b/zenxml/io.h
@@ -0,0 +1,124 @@
+// **************************************************************************
+// * 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 <cstdio>
+#include <cerrno>
+#include <zen/scope_guard.h>
+#include <zen/utf.h>
+#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 <class String> inline
+FILE* fopen(const String& filename, const wchar_t* mode)
+{
+#ifdef _MSC_VER
+ FILE* handle = nullptr;
+ errno_t rv = ::_wfopen_s(&handle, utfCvrtTo<std::wstring>(filename).c_str(), mode); //more secure?
+ (void)rv;
+ return handle;
+#else
+ return ::_wfopen(utfCvrtTo<std::wstring>(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 <class String>
+void saveStream(const std::string& stream, const String& filename) //throw XmlFileError
+{
+#ifdef ZEN_PLATFORM_WINDOWS
+ FILE* handle = implemenation::fopen(utfCvrtTo<std::wstring>(filename).c_str(), L"wb");
+#else
+ FILE* handle = ::fopen(utfCvrtTo<std::string>(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 <class String>
+std::string loadStream(const String& filename) //throw XmlFileError
+{
+#ifdef ZEN_PLATFORM_WINDOWS
+ FILE* handle = implemenation::fopen(utfCvrtTo<std::wstring>(filename).c_str(), L"rb");
+#else
+ FILE* handle = ::fopen(utfCvrtTo<std::string>(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
bgstack15