1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
// **************************************************************************
// * This file is part of the zen::Xml 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_WIN) && !defined(ZEN_LINUX) && !defined(ZEN_MAC)
#error Please specify your platform: #define ZEN_WIN, ZEN_LINUX or ZEN_MAC
#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_WIN
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_WIN
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_WIN
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
|