• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  Copyright (c) 2020 Alexander Grund
3 //
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)
7 //
8 
9 #define BOOST_NOWIDE_SOURCE
10 
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
19 #else
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
27 #endif
28 
29 #define BOOST_NOWIDE_FTELL ftello
30 #define BOOST_NOWIDE_FSEEK fseeko
31 #define BOOST_NOWIDE_OFF_T off_t
32 #endif
33 
34 #include <boost/nowide/filebuf.hpp>
35 #include <cassert>
36 #include <cstdint>
37 #include <limits>
38 #include <stdio.h>
39 #include <type_traits>
40 
41 namespace boost {
42 namespace nowide {
43     namespace detail {
44 
45         template<typename T, typename U>
is_in_range(U value)46         constexpr bool is_in_range(U value)
47         {
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();
52         }
53 
54         template<typename T, typename U>
cast_if_valid_or_minus_one(U value)55         T cast_if_valid_or_minus_one(U value)
56         {
57             return is_in_range<T>(value) ? static_cast<T>(value) : T(-1);
58         }
59 
ftell(FILE * file)60         std::streampos ftell(FILE* file)
61         {
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);
68         }
69 
fseek(FILE * file,std::streamoff offset,int origin)70         int fseek(FILE* file, std::streamoff offset, int origin)
71         {
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))
75                 return -1;
76             return BOOST_NOWIDE_FSEEK(file, static_cast<BOOST_NOWIDE_OFF_T>(offset), origin);
77         }
78     } // namespace detail
79 } // namespace nowide
80 } // namespace boost
81