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