changeset 4342:52166629239f

SystemToolbox::ReadFileRange()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 03 Dec 2020 18:48:06 +0100
parents 977c2759eb0a
children e1e918e790e8
files OrthancFramework/Sources/SystemToolbox.cpp OrthancFramework/Sources/SystemToolbox.h OrthancFramework/Sources/TemporaryFile.cpp OrthancFramework/Sources/TemporaryFile.h OrthancFramework/UnitTestsSources/FrameworkTests.cpp
diffstat 5 files changed, 125 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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_t>(size));
+
+    if (static_cast<std::streamsize>(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<uint64_t>(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<size_t>(end - start));
+
+      if (static_cast<uint64_t>(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<std::streamsize>(content.size()));
+      }
+    }
+    else
+    {
+      content.clear();
+    }
+
+    f.close();
+  }
 }
--- 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);
   };
 }
--- 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);
+  }
 }
--- 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;
   };
 }
--- 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