1  
//
1  
//
2  
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2025 Mohammad Nejati
3  
// Copyright (c) 2025 Mohammad Nejati
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
//
7  
//
8  
// Official repository: https://github.com/cppalliance/http
8  
// Official repository: https://github.com/cppalliance/http
9  
//
9  
//
10  

10  

11  
#ifndef BOOST_HTTP_FILE_HPP
11  
#ifndef BOOST_HTTP_FILE_HPP
12  
#define BOOST_HTTP_FILE_HPP
12  
#define BOOST_HTTP_FILE_HPP
13  

13  

14  
#include <boost/http/detail/config.hpp>
14  
#include <boost/http/detail/config.hpp>
15  
#include <boost/http/detail/except.hpp>
15  
#include <boost/http/detail/except.hpp>
16  
#include <boost/http/detail/file_posix.hpp>
16  
#include <boost/http/detail/file_posix.hpp>
17  
#include <boost/http/detail/file_stdio.hpp>
17  
#include <boost/http/detail/file_stdio.hpp>
18  
#include <boost/http/detail/file_win32.hpp>
18  
#include <boost/http/detail/file_win32.hpp>
19  
#include <boost/http/file_mode.hpp>
19  
#include <boost/http/file_mode.hpp>
20  

20  

21  
namespace boost {
21  
namespace boost {
22  
namespace http {
22  
namespace http {
23  

23  

24  
/** A platform-independent file stream.
24  
/** A platform-independent file stream.
25  

25  

26  
    This class provides a portable interface for
26  
    This class provides a portable interface for
27  
    reading from and writing to files. 
27  
    reading from and writing to files. 
28  
*/
28  
*/
29  
class file
29  
class file
30  
{
30  
{
31  
#if BOOST_HTTP_USE_WIN32_FILE
31  
#if BOOST_HTTP_USE_WIN32_FILE
32  
    using impl_type = detail::file_win32;
32  
    using impl_type = detail::file_win32;
33  
#elif BOOST_HTTP_USE_POSIX_FILE
33  
#elif BOOST_HTTP_USE_POSIX_FILE
34  
    using impl_type = detail::file_posix;
34  
    using impl_type = detail::file_posix;
35  
#else
35  
#else
36  
    using impl_type = detail::file_stdio;
36  
    using impl_type = detail::file_stdio;
37  
#endif
37  
#endif
38  

38  

39  
    impl_type impl_;
39  
    impl_type impl_;
40  

40  

41  
public:
41  
public:
42  
    /** The type of the underlying native file handle.
42  
    /** The type of the underlying native file handle.
43  

43  

44  
        This type is platform-specific.
44  
        This type is platform-specific.
45  
    */
45  
    */
46  
    using native_handle_type = impl_type::native_handle_type;
46  
    using native_handle_type = impl_type::native_handle_type;
47  

47  

48  
    /** Constructor.
48  
    /** Constructor.
49  

49  

50  
        There is no open file initially.
50  
        There is no open file initially.
51  
    */
51  
    */
52  
    file() = default;
52  
    file() = default;
53  

53  

54  
    /** Constructor.
54  
    /** Constructor.
55  

55  

56  
        Open a file at the given path with the specified mode.
56  
        Open a file at the given path with the specified mode.
57  

57  

58  
        @par Exception Safety
58  
        @par Exception Safety
59  
        Exception thrown if operation fails.
59  
        Exception thrown if operation fails.
60  

60  

61  
        @throw system_error
61  
        @throw system_error
62  
        Operation fails.
62  
        Operation fails.
63  

63  

64  
        @param path The UTF-8 encoded path to the file.
64  
        @param path The UTF-8 encoded path to the file.
65  

65  

66  
        @param mode The file mode to use.
66  
        @param mode The file mode to use.
67  

67  

68  
        @see
68  
        @see
69  
            @ref file_mode,
69  
            @ref file_mode,
70  
            @ref open.
70  
            @ref open.
71  
    */
71  
    */
72  
    file(char const* path, file_mode mode)
72  
    file(char const* path, file_mode mode)
73  
    {
73  
    {
74  
        open(path, mode);
74  
        open(path, mode);
75  
    }
75  
    }
76  

76  

77  
    /** Constructor.
77  
    /** Constructor.
78  

78  

79  
        The moved-from object behaves as if default-constructed.
79  
        The moved-from object behaves as if default-constructed.
80  
    */
80  
    */
81  
    file(file&& other) noexcept = default;
81  
    file(file&& other) noexcept = default;
82  

82  

83  
    /** Assignment
83  
    /** Assignment
84  

84  

85  
        The moved-from object behaves as if default-constructed.
85  
        The moved-from object behaves as if default-constructed.
86  
    */
86  
    */
87  
    file&
87  
    file&
88  
    operator=(
88  
    operator=(
89  
        file&& other) noexcept = default;
89  
        file&& other) noexcept = default;
90  

90  

91  
    /** Destructor
91  
    /** Destructor
92  

92  

93  
        If the file is open it is first closed.
93  
        If the file is open it is first closed.
94  
    */
94  
    */
95  
    ~file() = default;
95  
    ~file() = default;
96  

96  

97  
    /** Returns the native handle associated with the file.
97  
    /** Returns the native handle associated with the file.
98  
    */
98  
    */
99  
    native_handle_type
99  
    native_handle_type
100  
    native_handle()
100  
    native_handle()
101  
    {
101  
    {
102  
        return impl_.native_handle();
102  
        return impl_.native_handle();
103  
    }
103  
    }
104  

104  

105  
    /** Set the native file handle.
105  
    /** Set the native file handle.
106  

106  

107  
        If the file is open it is first closed.
107  
        If the file is open it is first closed.
108  

108  

109  
        @param h The native handle to assign.
109  
        @param h The native handle to assign.
110  
    */
110  
    */
111  
    void
111  
    void
112  
    native_handle(native_handle_type h)
112  
    native_handle(native_handle_type h)
113  
    {
113  
    {
114  
        impl_.native_handle(h);
114  
        impl_.native_handle(h);
115  
    }
115  
    }
116  

116  

117  
    /** Return true if the file is open.
117  
    /** Return true if the file is open.
118  
    */
118  
    */
119  
    bool
119  
    bool
120  
    is_open() const
120  
    is_open() const
121  
    {
121  
    {
122  
        return impl_.is_open();
122  
        return impl_.is_open();
123  
    }
123  
    }
124  

124  

125  
    /** Close the file if open.
125  
    /** Close the file if open.
126  

126  

127  
        Note that, The descriptor is closed even if the function
127  
        Note that, The descriptor is closed even if the function
128  
        reports an error.
128  
        reports an error.
129  

129  

130  
        @param ec Set to the error, if any occurred.
130  
        @param ec Set to the error, if any occurred.
131  
    */
131  
    */
132  
    void
132  
    void
133  
    close(system::error_code& ec)
133  
    close(system::error_code& ec)
134  
    {
134  
    {
135  
        impl_.close(ec);
135  
        impl_.close(ec);
136  
    }
136  
    }
137  

137  

138  
    /** Close the file if open.
138  
    /** Close the file if open.
139  

139  

140  
        Note that, The descriptor is closed even if the function
140  
        Note that, The descriptor is closed even if the function
141  
        reports an error.
141  
        reports an error.
142  

142  

143  
        @par Exception Safety
143  
        @par Exception Safety
144  
        Exception thrown if operation fails.
144  
        Exception thrown if operation fails.
145  

145  

146  
        @throw system_error
146  
        @throw system_error
147  
        Operation fails.
147  
        Operation fails.
148  
    */
148  
    */
149  
    void
149  
    void
150  
    close()
150  
    close()
151  
    {
151  
    {
152  
        system::error_code ec;
152  
        system::error_code ec;
153  
        impl_.close(ec);
153  
        impl_.close(ec);
154  
        if(ec)
154  
        if(ec)
155  
            detail::throw_system_error(ec);
155  
            detail::throw_system_error(ec);
156  
    }
156  
    }
157  

157  

158  
    /** Open a file at the given path with the specified mode.
158  
    /** Open a file at the given path with the specified mode.
159  

159  

160  
        @param path The UTF-8 encoded path to the file.
160  
        @param path The UTF-8 encoded path to the file.
161  

161  

162  
        @param mode The file mode to use.
162  
        @param mode The file mode to use.
163  

163  

164  
        @param ec Set to the error, if any occurred.
164  
        @param ec Set to the error, if any occurred.
165  

165  

166  
        @see
166  
        @see
167  
            @ref file_mode.
167  
            @ref file_mode.
168  
    */
168  
    */
169  
    void
169  
    void
170  
    open(char const* path, file_mode mode, system::error_code& ec)
170  
    open(char const* path, file_mode mode, system::error_code& ec)
171  
    {
171  
    {
172  
        impl_.open(path, mode, ec);
172  
        impl_.open(path, mode, ec);
173  
    }
173  
    }
174  

174  

175  
    /** Open a file at the given path with the specified mode.
175  
    /** Open a file at the given path with the specified mode.
176  

176  

177  
        @param path The UTF-8 encoded path to the file.
177  
        @param path The UTF-8 encoded path to the file.
178  

178  

179  
        @param mode The file mode to use.
179  
        @param mode The file mode to use.
180  

180  

181  
        @par Exception Safety
181  
        @par Exception Safety
182  
        Exception thrown if operation fails.
182  
        Exception thrown if operation fails.
183  

183  

184  
        @throw system_error
184  
        @throw system_error
185  
        Operation fails.
185  
        Operation fails.
186  

186  

187  
        @see
187  
        @see
188  
            @ref file_mode.
188  
            @ref file_mode.
189  
    */
189  
    */
190  
    void
190  
    void
191  
    open(char const* path, file_mode mode)
191  
    open(char const* path, file_mode mode)
192  
    {
192  
    {
193  
        system::error_code ec;
193  
        system::error_code ec;
194  
        impl_.open(path, mode, ec);
194  
        impl_.open(path, mode, ec);
195  
        if(ec)
195  
        if(ec)
196  
            detail::throw_system_error(ec);
196  
            detail::throw_system_error(ec);
197  
    }
197  
    }
198  

198  

199  
    /** Return the size of the open file in bytes.
199  
    /** Return the size of the open file in bytes.
200  

200  

201  
        @param ec Set to the error, if any occurred.
201  
        @param ec Set to the error, if any occurred.
202  
    */
202  
    */
203  
    std::uint64_t
203  
    std::uint64_t
204  
    size(system::error_code& ec) const
204  
    size(system::error_code& ec) const
205  
    {
205  
    {
206  
        return impl_.size(ec);
206  
        return impl_.size(ec);
207  
    }
207  
    }
208  

208  

209  
    /** Return the size of the open file in bytes.
209  
    /** Return the size of the open file in bytes.
210  

210  

211  
        @par Exception Safety
211  
        @par Exception Safety
212  
        Exception thrown if operation fails.
212  
        Exception thrown if operation fails.
213  

213  

214  
        @throw system_error
214  
        @throw system_error
215  
        Operation fails.
215  
        Operation fails.
216  
    */
216  
    */
217  
    std::uint64_t
217  
    std::uint64_t
218  
    size() const
218  
    size() const
219  
    {
219  
    {
220  
        system::error_code ec;
220  
        system::error_code ec;
221  
        auto r = impl_.size(ec);
221  
        auto r = impl_.size(ec);
222  
        if(ec)
222  
        if(ec)
223  
            detail::throw_system_error(ec);
223  
            detail::throw_system_error(ec);
224  
        return r;
224  
        return r;
225  
    }
225  
    }
226  

226  

227  
    /** Return the current position in the file, in bytes from the beginning.
227  
    /** Return the current position in the file, in bytes from the beginning.
228  

228  

229  
        @param ec Set to the error, if any occurred.
229  
        @param ec Set to the error, if any occurred.
230  
    */
230  
    */
231  
    std::uint64_t
231  
    std::uint64_t
232  
    pos(system::error_code& ec) const
232  
    pos(system::error_code& ec) const
233  
    {
233  
    {
234  
        return impl_.pos(ec);
234  
        return impl_.pos(ec);
235  
    }
235  
    }
236  

236  

237  
    /** Return the current position in the file, in bytes from the beginning.
237  
    /** Return the current position in the file, in bytes from the beginning.
238  

238  

239  
        @par Exception Safety
239  
        @par Exception Safety
240  
        Exception thrown if operation fails.
240  
        Exception thrown if operation fails.
241  

241  

242  
        @throw system_error
242  
        @throw system_error
243  
        Operation fails.
243  
        Operation fails.
244  
    */
244  
    */
245  
    std::uint64_t
245  
    std::uint64_t
246  
    pos() const
246  
    pos() const
247  
    {
247  
    {
248  
        system::error_code ec;
248  
        system::error_code ec;
249  
        auto r = impl_.pos(ec);
249  
        auto r = impl_.pos(ec);
250  
        if(ec)
250  
        if(ec)
251  
            detail::throw_system_error(ec);
251  
            detail::throw_system_error(ec);
252  
        return r;
252  
        return r;
253  
    }
253  
    }
254  

254  

255  
    /** Set the current position in the file.
255  
    /** Set the current position in the file.
256  

256  

257  
        @param offset The byte offset from the beginning of the file.
257  
        @param offset The byte offset from the beginning of the file.
258  

258  

259  
        @param ec Set to the error, if any occurred.
259  
        @param ec Set to the error, if any occurred.
260  
    */
260  
    */
261  
    void
261  
    void
262  
    seek(std::uint64_t offset, system::error_code& ec)
262  
    seek(std::uint64_t offset, system::error_code& ec)
263  
    {
263  
    {
264  
        impl_.seek(offset, ec);
264  
        impl_.seek(offset, ec);
265  
    }
265  
    }
266  

266  

267  
    /** Set the current position in the file.
267  
    /** Set the current position in the file.
268  

268  

269  
        @par Exception Safety
269  
        @par Exception Safety
270  
        Exception thrown if operation fails.
270  
        Exception thrown if operation fails.
271  

271  

272  
        @throw system_error
272  
        @throw system_error
273  
        Operation fails.
273  
        Operation fails.
274  

274  

275  
        @param offset The byte offset from the beginning of the file.
275  
        @param offset The byte offset from the beginning of the file.
276  
    */
276  
    */
277  
    void
277  
    void
278  
    seek(std::uint64_t offset)
278  
    seek(std::uint64_t offset)
279  
    {
279  
    {
280  
        system::error_code ec;
280  
        system::error_code ec;
281  
        impl_.seek(offset, ec);
281  
        impl_.seek(offset, ec);
282  
        if(ec)
282  
        if(ec)
283  
            detail::throw_system_error(ec);
283  
            detail::throw_system_error(ec);
284  
    }
284  
    }
285  

285  

286  
    /** Read data from the file.
286  
    /** Read data from the file.
287  

287  

288  
        @return The number of bytes read. Returns
288  
        @return The number of bytes read. Returns
289  
        0 on end-of-file or if an error occurs (in
289  
        0 on end-of-file or if an error occurs (in
290  
        which case @p ec is set).
290  
        which case @p ec is set).
291  

291  

292  
        @param buffer The buffer to store the read data.
292  
        @param buffer The buffer to store the read data.
293  

293  

294  
        @param n The number of bytes to read.
294  
        @param n The number of bytes to read.
295  

295  

296  
        @param ec Set to the error, if any occurred.
296  
        @param ec Set to the error, if any occurred.
297  
    */
297  
    */
298  
    std::size_t
298  
    std::size_t
299  
    read(void* buffer, std::size_t n, system::error_code& ec)
299  
    read(void* buffer, std::size_t n, system::error_code& ec)
300  
    {
300  
    {
301  
        return impl_.read(buffer, n, ec);
301  
        return impl_.read(buffer, n, ec);
302  
    }
302  
    }
303  

303  

304  
    /** Read data from the file.
304  
    /** Read data from the file.
305  

305  

306  
        @par Exception Safety
306  
        @par Exception Safety
307  
        Exception thrown if operation fails.
307  
        Exception thrown if operation fails.
308  

308  

309  
        @throw system_error
309  
        @throw system_error
310  
        Operation fails.
310  
        Operation fails.
311  

311  

312  
        @return The number of bytes read. Returns
312  
        @return The number of bytes read. Returns
313  
        0 on end-of-file.
313  
        0 on end-of-file.
314  

314  

315  
        @param buffer The buffer to store the read data.
315  
        @param buffer The buffer to store the read data.
316  

316  

317  
        @param n The number of bytes to read.
317  
        @param n The number of bytes to read.
318  
    */
318  
    */
319  
    std::size_t
319  
    std::size_t
320  
    read(void* buffer, std::size_t n)
320  
    read(void* buffer, std::size_t n)
321  
    {
321  
    {
322  
        system::error_code ec;
322  
        system::error_code ec;
323  
        auto r = impl_.read(buffer, n, ec);
323  
        auto r = impl_.read(buffer, n, ec);
324  
        if(ec)
324  
        if(ec)
325  
            detail::throw_system_error(ec);
325  
            detail::throw_system_error(ec);
326  
        return r;
326  
        return r;
327  
    }
327  
    }
328  

328  

329  
    /** Write data to the file.
329  
    /** Write data to the file.
330  

330  

331  
        @return The number of bytes written.
331  
        @return The number of bytes written.
332  
        Returns 0 on error (in which case @p ec is
332  
        Returns 0 on error (in which case @p ec is
333  
        set).
333  
        set).
334  

334  

335  
        @param buffer The buffer containing the data to write.
335  
        @param buffer The buffer containing the data to write.
336  

336  

337  
        @param n The number of bytes to write.
337  
        @param n The number of bytes to write.
338  

338  

339  
        @param ec Set to the error, if any occurred.
339  
        @param ec Set to the error, if any occurred.
340  
    */
340  
    */
341  
    std::size_t
341  
    std::size_t
342  
    write(void const* buffer, std::size_t n, system::error_code& ec)
342  
    write(void const* buffer, std::size_t n, system::error_code& ec)
343  
    {
343  
    {
344  
        return impl_.write(buffer, n, ec);
344  
        return impl_.write(buffer, n, ec);
345  
    }
345  
    }
346  

346  

347  
    /** Write data to the file.
347  
    /** Write data to the file.
348  

348  

349  
        @par Exception Safety
349  
        @par Exception Safety
350  
        Exception thrown if operation fails.
350  
        Exception thrown if operation fails.
351  

351  

352  
        @throw system_error
352  
        @throw system_error
353  
        Operation fails.
353  
        Operation fails.
354  

354  

355  
        @return The number of bytes written.
355  
        @return The number of bytes written.
356  

356  

357  
        @param buffer The buffer containing the data to write.
357  
        @param buffer The buffer containing the data to write.
358  

358  

359  
        @param n The number of bytes to write.
359  
        @param n The number of bytes to write.
360  
    */
360  
    */
361  
    std::size_t
361  
    std::size_t
362  
    write(void const* buffer, std::size_t n)
362  
    write(void const* buffer, std::size_t n)
363  
    {
363  
    {
364  
        system::error_code ec;
364  
        system::error_code ec;
365  
        auto r = impl_.write(buffer, n, ec);
365  
        auto r = impl_.write(buffer, n, ec);
366  
        if(ec)
366  
        if(ec)
367  
            detail::throw_system_error(ec);
367  
            detail::throw_system_error(ec);
368  
        return r;
368  
        return r;
369  
    }
369  
    }
370  
};
370  
};
371  

371  

372  
} // http
372  
} // http
373  
} // boost
373  
} // boost
374  

374  

375  
#endif
375  
#endif