| 3983 | |
| 3984 | template<typename T> |
| 3985 | PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size) |
| 3986 | { |
| 3987 | // get length of remaining data in stream |
| 3988 | typename std::basic_istream<T>::pos_type pos = stream.tellg(); |
| 3989 | stream.seekg(0, std::ios::end); |
| 3990 | std::streamoff length = stream.tellg() - pos; |
| 3991 | stream.seekg(pos); |
| 3992 | |
| 3993 | if (stream.fail() || pos < 0) |
| 3994 | return status_io_error; |
| 3995 | |
| 3996 | // guard against huge files |
| 3997 | size_t read_length = static_cast<size_t>(length); |
| 3998 | |
| 3999 | if (static_cast<std::streamsize>(read_length) != length || length < 0) |
| 4000 | return status_out_of_memory; |
| 4001 | |
| 4002 | // read stream data into memory (guard against stream exceptions with buffer holder) |
| 4003 | buffer_holder buffer(xml_memory::allocate((read_length > 0 ? read_length : 1) * sizeof(T)), xml_memory::deallocate); |
| 4004 | if (!buffer.data) |
| 4005 | return status_out_of_memory; |
| 4006 | |
| 4007 | stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length)); |
| 4008 | |
| 4009 | // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors |
| 4010 | if (stream.bad() || (!stream.eof() && stream.fail())) |
| 4011 | return status_io_error; |
| 4012 | |
| 4013 | // return buffer |
| 4014 | size_t actual_length = static_cast<size_t>(stream.gcount()); |
| 4015 | assert(actual_length <= read_length); |
| 4016 | |
| 4017 | *out_buffer = buffer.release(); |
| 4018 | *out_size = actual_length * sizeof(T); |
| 4019 | |
| 4020 | return status_ok; |
| 4021 | } |
| 4022 | |
| 4023 | template<typename T> |
| 4024 | PUGI__FN xml_parse_result |