2 // Copyright (c) 2020 Alexander Grund
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
9 #define BOOST_NOWIDE_SOURCE
11 #ifdef BOOST_NOWIDE_NO_LFS
12 #define BOOST_NOWIDE_FTELL ::ftell
13 #define BOOST_NOWIDE_FSEEK ::fseek
14 #define BOOST_NOWIDE_OFF_T long
15 #elif defined(_WIN32) && !defined(__CYGWIN__)
16 #define BOOST_NOWIDE_FTELL _ftelli64
17 #define BOOST_NOWIDE_FSEEK _fseeki64
18 #define BOOST_NOWIDE_OFF_T int64_t
20 // IMPORTANT: Have these defines BEFORE any #includes
21 // and make sure changes by those macros don't leak into the public interface
22 // Make LFS functions available
23 #define _LARGEFILE_SOURCE
24 // Make off_t 64 bits if the macro isn't set
25 #ifndef _FILE_OFFSET_BITS
26 #define _FILE_OFFSET_BITS 64
29 #define BOOST_NOWIDE_FTELL ftello
30 #define BOOST_NOWIDE_FSEEK fseeko
31 #define BOOST_NOWIDE_OFF_T off_t
34 #include <boost/nowide/filebuf.hpp>
39 #include <type_traits>
45 template<typename T
, typename U
>
46 constexpr bool is_in_range(U value
)
48 static_assert(std::is_signed
<T
>::value
== std::is_signed
<U
>::value
,
49 "Mixed sign comparison can lead to problems below");
50 // coverity[result_independent_of_operands]
51 return value
>= std::numeric_limits
<T
>::min() && value
<= std::numeric_limits
<T
>::max();
54 template<typename T
, typename U
>
55 T
cast_if_valid_or_minus_one(U value
)
57 return is_in_range
<T
>(value
) ? static_cast<T
>(value
) : T(-1);
60 std::streampos
ftell(FILE* file
)
62 const auto pos
= BOOST_NOWIDE_FTELL(file
);
63 // Note that this is used in seekoff for which the standard states:
64 // On success, it returns the new absolute position the internal position pointer points to after the call,
65 // if representable [...] [or] the function returns pos_type(off_type(-1)). Hence we do a range check first,
66 // then cast or return failure instead of silently truncating
67 return cast_if_valid_or_minus_one
<std::streamoff
>(pos
);
70 int fseek(FILE* file
, std::streamoff offset
, int origin
)
72 // Similar to above: If the value of offset can't fit inside target type
73 // don't silently truncate but fail right away
74 if(!is_in_range
<BOOST_NOWIDE_OFF_T
>(offset
))
76 return BOOST_NOWIDE_FSEEK(file
, static_cast<BOOST_NOWIDE_OFF_T
>(offset
), origin
);