summaryrefslogtreecommitdiff
path: root/zenxml/io.h
blob: 596d7acf7747837a6d7aa51a0b63734c43e8da41 (plain)
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
bgstack15