# HG changeset patch # User Sebastien Jodogne # Date 1607017686 -3600 # Node ID 52166629239f320702a0f8a8f7335145c81eb530 # Parent 977c2759eb0a8365c23967f79786f5d5eb083c18 SystemToolbox::ReadFileRange() diff -r 977c2759eb0a -r 52166629239f OrthancFramework/Sources/SystemToolbox.cpp --- a/OrthancFramework/Sources/SystemToolbox.cpp Thu Dec 03 18:15:47 2020 +0100 +++ b/OrthancFramework/Sources/SystemToolbox.cpp Thu Dec 03 18:48:06 2020 +0100 @@ -224,6 +224,13 @@ std::streamsize size = GetStreamSize(f); content.resize(static_cast(size)); + + if (static_cast(content.size()) != size) + { + throw OrthancException(ErrorCode_InternalError, + "Reading a file that is too large for a 32bit architecture"); + } + if (size != 0) { f.read(&content[0], size); @@ -807,4 +814,68 @@ return (base / relative).string(); } } + + + void SystemToolbox::ReadFileRange(std::string& content, + const std::string& path, + uint64_t start, // Inclusive + uint64_t end, // Exclusive + bool throwIfOverflow) + { + if (start > end) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + if (!IsRegularFile(path)) + { + throw OrthancException(ErrorCode_RegularFileExpected, + "The path does not point to a regular file: " + path); + } + + boost::filesystem::ifstream f; + f.open(path, std::ifstream::in | std::ifstream::binary); + if (!f.good()) + { + throw OrthancException(ErrorCode_InexistentFile, + "File not found: " + path); + } + + uint64_t fileSize = static_cast(GetStreamSize(f)); + if (end > fileSize) + { + if (throwIfOverflow) + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "Reading beyond the end of a file"); + } + else + { + end = fileSize; + } + } + + if (start <= end) + { + content.resize(static_cast(end - start)); + + if (static_cast(content.size()) != (end - start)) + { + throw OrthancException(ErrorCode_InternalError, + "Reading a file that is too large for a 32bit architecture"); + } + + if (!content.empty()) + { + f.seekg(start, std::ios::beg); + f.read(&content[0], static_cast(content.size())); + } + } + else + { + content.clear(); + } + + f.close(); + } } diff -r 977c2759eb0a -r 52166629239f OrthancFramework/Sources/SystemToolbox.h --- a/OrthancFramework/Sources/SystemToolbox.h Thu Dec 03 18:15:47 2020 +0100 +++ b/OrthancFramework/Sources/SystemToolbox.h Thu Dec 03 18:48:06 2020 +0100 @@ -113,5 +113,11 @@ static std::string InterpretRelativePath(const std::string& baseDirectory, const std::string& relativePath); + + static void ReadFileRange(std::string& content, + const std::string& path, + uint64_t start, // Inclusive + uint64_t end, // Exclusive + bool throwIfOverflow); }; } diff -r 977c2759eb0a -r 52166629239f OrthancFramework/Sources/TemporaryFile.cpp --- a/OrthancFramework/Sources/TemporaryFile.cpp Thu Dec 03 18:15:47 2020 +0100 +++ b/OrthancFramework/Sources/TemporaryFile.cpp Thu Dec 03 18:48:06 2020 +0100 @@ -138,4 +138,13 @@ { return SystemToolbox::GetFileSize(path_); } + + + void TemporaryFile::ReadRange(std::string& content, + uint64_t start, + uint64_t end, + bool throwIfOverflow) const + { + SystemToolbox::ReadFileRange(content, path_, start, end, throwIfOverflow); + } } diff -r 977c2759eb0a -r 52166629239f OrthancFramework/Sources/TemporaryFile.h --- a/OrthancFramework/Sources/TemporaryFile.h Thu Dec 03 18:15:47 2020 +0100 +++ b/OrthancFramework/Sources/TemporaryFile.h Thu Dec 03 18:48:06 2020 +0100 @@ -60,5 +60,10 @@ void Touch(); uint64_t GetFileSize() const; + + void ReadRange(std::string& content, + uint64_t start, + uint64_t end, + bool throwIfOverflow) const; }; } diff -r 977c2759eb0a -r 52166629239f OrthancFramework/UnitTestsSources/FrameworkTests.cpp --- a/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Thu Dec 03 18:15:47 2020 +0100 +++ b/OrthancFramework/UnitTestsSources/FrameworkTests.cpp Thu Dec 03 18:48:06 2020 +0100 @@ -1373,3 +1373,37 @@ } } #endif + + +#if ORTHANC_SANDBOXED != 1 +TEST(Toolbox, ReadFileRange) +{ + TemporaryFile tmp; + std::string s; + + tmp.Write(""); + tmp.Read(s); ASSERT_TRUE(s.empty()); + tmp.ReadRange(s, 0, 0, true); ASSERT_TRUE(s.empty()); + tmp.ReadRange(s, 0, 10, false); ASSERT_TRUE(s.empty()); + + ASSERT_THROW(tmp.ReadRange(s, 0, 1, true), OrthancException); + + tmp.Write("Hello"); + tmp.Read(s); ASSERT_EQ("Hello", s); + tmp.ReadRange(s, 0, 5, true); ASSERT_EQ("Hello", s); + tmp.ReadRange(s, 0, 1, true); ASSERT_EQ("H", s); + tmp.ReadRange(s, 1, 2, true); ASSERT_EQ("e", s); + tmp.ReadRange(s, 2, 3, true); ASSERT_EQ("l", s); + tmp.ReadRange(s, 3, 4, true); ASSERT_EQ("l", s); + tmp.ReadRange(s, 4, 5, true); ASSERT_EQ("o", s); + tmp.ReadRange(s, 2, 5, true); ASSERT_EQ("llo", s); + tmp.ReadRange(s, 2, 50, false); ASSERT_EQ("llo", s); + tmp.ReadRange(s, 2, 2, false); ASSERT_TRUE(s.empty()); + tmp.ReadRange(s, 10, 50, false); ASSERT_TRUE(s.empty()); + + ASSERT_THROW(tmp.ReadRange(s, 5, 10, true), OrthancException); + ASSERT_THROW(tmp.ReadRange(s, 10, 50, true), OrthancException); + ASSERT_THROW(tmp.ReadRange(s, 50, 10, true), OrthancException); + ASSERT_THROW(tmp.ReadRange(s, 2, 1, true), OrthancException); +} +#endif