summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorarseny.kapoulkine <arseny.kapoulkine@99668b35-9821-0410-8761-19e4c4f06640>2010-09-20 21:26:21 +0000
committerarseny.kapoulkine <arseny.kapoulkine@99668b35-9821-0410-8761-19e4c4f06640>2010-09-20 21:26:21 +0000
commit21b129a7e49f25b1963f3371a910272725013dff (patch)
treec0ba2d47e8ad715172a5dc8f618c77978a9a9343
parentb84eb7bdba7cb56b880c62a83eadd14108cac2db (diff)
Improved large file support: added overflow checks, _ftelli64/_fseeki64 are used on MSVC
git-svn-id: http://pugixml.googlecode.com/svn/trunk@743 99668b35-9821-0410-8761-19e4c4f06640
-rw-r--r--src/pugixml.cpp38
1 files changed, 31 insertions, 7 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 24b4a6a..5c327ff 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -2981,34 +2981,58 @@ namespace
{
if (!file) return make_parse_result(status_file_not_found);
+ // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick
+ #if defined(_MSC_VER) && _MSC_VER >= 1400
+ // there are 64-bit versions of fseek/ftell, let's use them
+ typedef __int64 length_type;
+
+ _fseeki64(file, 0, SEEK_END);
+ length_type length = _ftelli64(file);
+ _fseeki64(file, 0, SEEK_SET);
+ #else
+ // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway.
+ typedef long length_type;
+
fseek(file, 0, SEEK_END);
- long length = ftell(file);
+ length_type length = ftell(file);
fseek(file, 0, SEEK_SET);
+ #endif
+ // check for I/O errors
if (length < 0)
{
fclose(file);
return make_parse_result(status_io_error);
}
- char* s = static_cast<char*>(global_allocate(length > 0 ? length : 1));
+ // check for overflow
+ if (static_cast<length_type>(static_cast<size_t>(length)) != length)
+ {
+ fclose(file);
+ return make_parse_result(status_out_of_memory);
+ }
+
+ // allocate buffer for the whole file
+ size_t size = static_cast<size_t>(length);
+ char* contents = static_cast<char*>(global_allocate(length > 0 ? size : 1));
- if (!s)
+ if (!contents)
{
fclose(file);
return make_parse_result(status_out_of_memory);
}
- size_t read = fread(s, 1, (size_t)length, file);
+ // read file in memory
+ size_t read_size = fread(contents, 1, size, file);
fclose(file);
- if (read != (size_t)length)
+ if (read_size != size)
{
- global_deallocate(s);
+ global_deallocate(contents);
return make_parse_result(status_io_error);
}
- return doc.load_buffer_inplace_own(s, length, options, encoding);
+ return doc.load_buffer_inplace_own(contents, size, options, encoding);
}
#ifndef PUGIXML_NO_STL