| 3924 | |
| 3925 | template<typename T> |
| 3926 | PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size) |
| 3927 | { |
| 3928 | buffer_holder chunks(0, xml_stream_chunk<T>::destroy); |
| 3929 | |
| 3930 | // read file to a chunk list |
| 3931 | size_t total = 0; |
| 3932 | xml_stream_chunk<T>* last = nullptr; |
| 3933 | |
| 3934 | while (!stream.eof()) |
| 3935 | { |
| 3936 | // allocate new chunk |
| 3937 | xml_stream_chunk<T>* chunk = xml_stream_chunk<T>::create(); |
| 3938 | if (!chunk) |
| 3939 | return status_out_of_memory; |
| 3940 | |
| 3941 | // append chunk to list |
| 3942 | if (last) |
| 3943 | last = last->next = chunk; |
| 3944 | else |
| 3945 | chunks.data = last = chunk; |
| 3946 | |
| 3947 | // read data to chunk |
| 3948 | stream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T))); |
| 3949 | chunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T); |
| 3950 | |
| 3951 | // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors |
| 3952 | if (stream.bad() || (!stream.eof() && stream.fail())) |
| 3953 | return status_io_error; |
| 3954 | |
| 3955 | // guard against huge files (chunk size is small enough to make this overflow check work) |
| 3956 | if (total + chunk->size < total) |
| 3957 | return status_out_of_memory; |
| 3958 | total += chunk->size; |
| 3959 | } |
| 3960 | |
| 3961 | // copy chunk list to a contiguous buffer |
| 3962 | char* buffer = static_cast<char*>(xml_memory::allocate(total)); |
| 3963 | if (!buffer) |
| 3964 | return status_out_of_memory; |
| 3965 | |
| 3966 | char* write = buffer; |
| 3967 | |
| 3968 | for (xml_stream_chunk<T>* chunk = static_cast<xml_stream_chunk<T>*>(chunks.data); chunk; chunk = chunk->next) |
| 3969 | { |
| 3970 | assert(write + chunk->size <= buffer + total); |
| 3971 | memcpy(write, chunk->data, chunk->size); |
| 3972 | write += chunk->size; |
| 3973 | } |
| 3974 | |
| 3975 | assert(write == buffer + total); |
| 3976 | |
| 3977 | // return buffer |
| 3978 | *out_buffer = buffer; |
| 3979 | *out_size = total; |
| 3980 | |
| 3981 | return status_ok; |
| 3982 | } |
| 3983 | |