Index: include/AdblockPlus/DefaultFileSystem.h
===================================================================
--- a/include/AdblockPlus/DefaultFileSystem.h
+++ b/include/AdblockPlus/DefaultFileSystem.h
@@ -32,18 +32,18 @@
    * `FileSystem` implementation that interacts directly with the operating
    * system's file system.
    * All paths are considered relative to the base path, or to the current
    * working directory if no base path is set (see `SetBasePath()`).
    */
   class DefaultFileSystem : public FileSystem
   {
   public:
-    std::shared_ptr<std::istream> Read(const std::string& path) const;
-    void Write(const std::string& path, std::istream& data);
+    IOBuffer Read(const std::string& path) const;
+    void Write(const std::string& path, const IOBuffer& data);
     void Move(const std::string& fromPath, const std::string& toPath);
     void Remove(const std::string& path);
     StatResult Stat(const std::string& path) const;
     std::string Resolve(const std::string& path) const;
 
     /**
      * Sets the base path, all paths are considered relative to it.
      * @param path Base path.
Index: include/AdblockPlus/FileSystem.h
===================================================================
--- a/include/AdblockPlus/FileSystem.h
+++ b/include/AdblockPlus/FileSystem.h
@@ -60,33 +60,34 @@
       bool isFile;
 
       /**
        * POSIX time of the last modification.
        */
       int64_t lastModified;
     };
 
+    typedef std::vector<uint8_t> IOBuffer;
+
     virtual ~FileSystem() {}
 
     /**
      * Reads from a file.
      * @param path File path.
-     * @return Input stream with the file's contents.
+     * @return Buffer with the file content.
      */
-    virtual std::shared_ptr<std::istream>
-      Read(const std::string& path) const = 0;
+    virtual IOBuffer Read(const std::string& path) const = 0;
 
     /**
      * Writes to a file.
      * @param path File path.
-     * @param data Input stream with the data to write.
+     * @param data Buffer with the data to write.
      */
     virtual void Write(const std::string& path,
-                       std::istream& data) = 0;
+                       const IOBuffer& data) = 0;
 
     /**
      * Moves a file (i.e.\ renames it).
      * @param fromPath Current path to the file.
      * @param toPath New path to the file.
      */
     virtual void Move(const std::string& fromPath,
                       const std::string& toPath) = 0;
Index: src/DefaultFileSystem.cpp
===================================================================
--- a/src/DefaultFileSystem.cpp
+++ b/src/DefaultFileSystem.cpp
@@ -61,30 +61,39 @@
   // file paths as they are.
   std::string NormalizePath(const std::string& path)
   {
     return path;
   }
 #endif
 }
 
-std::shared_ptr<std::istream>
+FileSystem::IOBuffer
 DefaultFileSystem::Read(const std::string& path) const
 {
-  std::shared_ptr<std::istream> result(new std::ifstream(NormalizePath(path).c_str()));
-  if (result->fail())
+  std::ifstream file(NormalizePath(path).c_str(), std::ios_base::binary);
+  if (file.fail())
     throw RuntimeErrorWithErrno("Failed to open " + path);
-  return result;
+
+  file.seekg(0, std::ios_base::end);
+  auto dataSize = file.tellg();
+  file.seekg(0, std::ios_base::beg);
+
+  IOBuffer data(dataSize);
+  file.read(reinterpret_cast<std::ifstream::char_type*>(data.data()),
+            data.size());
+  return data;
 }
 
 void DefaultFileSystem::Write(const std::string& path,
-                              std::istream& data)
+                              const IOBuffer& data)
 {
   std::ofstream file(NormalizePath(path).c_str(), std::ios_base::out | std::ios_base::binary);
-  file << Utils::Slurp(data);
+  file.write(reinterpret_cast<const std::ofstream::char_type*>(data.data()),
+             data.size());
 }
 
 void DefaultFileSystem::Move(const std::string& fromPath,
                              const std::string& toPath)
 {
   if (rename(NormalizePath(fromPath).c_str(), NormalizePath(toPath).c_str()))
     throw RuntimeErrorWithErrno("Failed to move " + fromPath + " to " + toPath);
 }
Index: src/FileSystemJsObject.cpp
===================================================================
--- a/src/FileSystemJsObject.cpp
+++ b/src/FileSystemJsObject.cpp
@@ -56,18 +56,18 @@
     }
 
     void Run()
     {
       std::string content;
       std::string error;
       try
       {
-        std::shared_ptr<std::istream> stream = fileSystem->Read(path);
-        content = Utils::Slurp(*stream);
+        auto buffer = fileSystem->Read(path);
+        content = std::string(buffer.cbegin(), buffer.cend());
       }
       catch (std::exception& e)
       {
         error = e.what();
       }
       catch (...)
       {
         error =  "Unknown error while reading from " + path;
@@ -95,19 +95,18 @@
     {
     }
 
     void Run()
     {
       std::string error;
       try
       {
-        std::stringstream stream;
-        stream << content;
-        fileSystem->Write(path, stream);
+        FileSystem::IOBuffer buffer(content.cbegin(), content.cend());
+        fileSystem->Write(path, buffer);
       }
       catch (std::exception& e)
       {
         error = e.what();
       }
       catch (...)
       {
         error = "Unknown error while writing to " + path;
Index: src/Utils.cpp
===================================================================
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -10,35 +10,27 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <sstream>
 #include <stdexcept>
 
 #ifdef _WIN32
 #include <Windows.h>
 #include <Shlwapi.h>
 #endif
 
 #include "Utils.h"
 
 using namespace AdblockPlus;
 
-std::string Utils::Slurp(std::istream& stream)
-{
-  std::stringstream content;
-  content << stream.rdbuf();
-  return content.str();
-}
-
 std::string Utils::FromV8String(const v8::Handle<v8::Value>& value)
 {
   v8::String::Utf8Value stringValue(value);
   if (stringValue.length())
     return std::string(*stringValue, stringValue.length());
   else
     return std::string();
 }
Index: src/Utils.h
===================================================================
--- a/src/Utils.h
+++ b/src/Utils.h
@@ -16,25 +16,23 @@
  */
 
 #ifndef ADBLOCK_PLUS_UTILS_H
 #define ADBLOCK_PLUS_UTILS_H
 
 #include <algorithm>
 #include <cctype>
 #include <functional>
-#include <istream>
 #include <string>
 #include <v8.h>
 
 namespace AdblockPlus
 {
   namespace Utils
   {
-    std::string Slurp(std::istream& stream);
     std::string FromV8String(const v8::Handle<v8::Value>& value);
     v8::Local<v8::String> ToV8String(v8::Isolate* isolate, const std::string& str);
     void ThrowExceptionInJS(v8::Isolate* isolate, const std::string& str);
 
     // Code for templated function has to be in a header file, can't be in .cpp
     template<class T>
     T TrimString(const T& text)
     {
Index: test/BaseJsTest.h
===================================================================
--- a/test/BaseJsTest.h
+++ b/test/BaseJsTest.h
@@ -100,22 +100,22 @@
   {
     throw std::runtime_error("Unexpected error: " + message);
   }
 };
 
 class ThrowingFileSystem : public AdblockPlus::FileSystem
 {
 public:
-  std::shared_ptr<std::istream> Read(const std::string& path) const
+  FileSystem::IOBuffer Read(const std::string& path) const
   {
     throw std::runtime_error("Not implemented");
   }
 
-  void Write(const std::string& path, std::istream& content)
+  void Write(const std::string& path, const FileSystem::IOBuffer& content)
   {
     throw std::runtime_error("Not implemented");
   }
 
   void Move(const std::string& fromPath, const std::string& toPath)
   {
     throw std::runtime_error("Not implemented");
   }
@@ -144,27 +144,27 @@
   {
     throw std::runtime_error("Unexpected GET: " + url);
   }
 };
 
 class LazyFileSystem : public AdblockPlus::FileSystem
 {
 public:
-  std::shared_ptr<std::istream> Read(const std::string& path) const
+  IOBuffer Read(const std::string& path) const
   {
     std::string dummyData("");
     if (path == "patterns.ini")
       dummyData = "# Adblock Plus preferences\n[Subscription]\nurl=~fl~";
     else if (path == "prefs.json")
       dummyData = "{}";
-    return std::shared_ptr<std::istream>(new std::istringstream(dummyData));
+    return IOBuffer(dummyData.cbegin(), dummyData.cend());
   }
 
-  void Write(const std::string& path, std::istream& content)
+  void Write(const std::string& path, const IOBuffer& content)
   {
   }
 
   void Move(const std::string& fromPath, const std::string& toPath)
   {
   }
 
   void Remove(const std::string& path)
Index: test/DefaultFileSystem.cpp
===================================================================
--- a/test/DefaultFileSystem.cpp
+++ b/test/DefaultFileSystem.cpp
@@ -21,30 +21,28 @@
 
 namespace
 {
   const std::string testPath = "libadblockplus-t\xc3\xa4st-file";
 
   void WriteString(AdblockPlus::FileSystem& fileSystem,
                    const std::string& content)
   {
-    std::stringstream input;
-    input << content;
-    fileSystem.Write(testPath, input);
+    AdblockPlus::FileSystem::IOBuffer buffer(content.cbegin(), content.cend());
+    fileSystem.Write(testPath, buffer);
   }
 }
 
 TEST(DefaultFileSystemTest, WriteReadRemove)
 {
   AdblockPlus::DefaultFileSystem fileSystem;
   WriteString(fileSystem, "foo");
-  std::stringstream output;
-  output << fileSystem.Read(testPath)->rdbuf();
+  auto output = fileSystem.Read(testPath);
   fileSystem.Remove(testPath);
-  ASSERT_EQ("foo", output.str());
+  ASSERT_EQ("foo", std::string(output.cbegin(), output.cend()));
 }
 
 TEST(DefaultFileSystemTest, StatWorkingDirectory)
 {
   AdblockPlus::DefaultFileSystem fileSystem;
   const AdblockPlus::FileSystem::StatResult result = fileSystem.Stat(".");
   ASSERT_TRUE(result.exists);
   ASSERT_TRUE(result.isDirectory);
Index: test/FileSystemJsObject.cpp
===================================================================
--- a/test/FileSystemJsObject.cpp
+++ b/test/FileSystemJsObject.cpp
@@ -20,50 +20,45 @@
 #include "../src/Thread.h"
 
 namespace
 {
   class MockFileSystem : public AdblockPlus::FileSystem
   {
   public:
     bool success;
-    std::string contentToRead;
+    IOBuffer contentToRead;
     std::string lastWrittenPath;
-    std::string lastWrittenContent;
+    IOBuffer lastWrittenContent;
     std::string movedFrom;
     std::string movedTo;
     std::string removedPath;
     mutable std::string statPath;
     bool statExists;
     bool statIsDirectory;
     bool statIsFile;
     int statLastModified;
 
     MockFileSystem() : success(true)
     {
     }
 
-    std::shared_ptr<std::istream> Read(const std::string& path) const
+    IOBuffer Read(const std::string& path) const
     {
       if (!success)
         throw std::runtime_error("Unable to read " + path);
-      std::stringstream* const stream = new std::stringstream;
-      *stream << contentToRead;
-      return std::shared_ptr<std::istream>(stream);
+      return contentToRead;
     }
 
-    void Write(const std::string& path, std::istream& data)
+    void Write(const std::string& path, const IOBuffer& data)
     {
       if (!success)
         throw std::runtime_error("Unable to write to " + path);
       lastWrittenPath = path;
-
-      std::stringstream content;
-      content << data.rdbuf();
-      lastWrittenContent = content.str();
+      lastWrittenContent = data;
     }
 
     void Move(const std::string& fromPath, const std::string& toPath)
     {
       if (!success)
         throw std::runtime_error("Unable to move " + fromPath + " to "
                                  + toPath);
       movedFrom = fromPath;
@@ -120,17 +115,18 @@
       mockFileSystem = MockFileSystemPtr(new MockFileSystem);
       jsEngine->SetFileSystem(mockFileSystem);
     }
   };
 }
 
 TEST_F(FileSystemJsObjectTest, Read)
 {
-  mockFileSystem->contentToRead = "foo";
+  mockFileSystem->contentToRead =
+    AdblockPlus::FileSystem::IOBuffer{'f', 'o', 'o'};
   std::string content;
   std::string error;
   ReadFile(jsEngine, content, error);
   ASSERT_EQ("foo", content);
   ASSERT_EQ("", error);
 }
 
 TEST_F(FileSystemJsObjectTest, ReadIllegalArguments)
@@ -149,17 +145,18 @@
   ASSERT_EQ("", content);
 }
 
 TEST_F(FileSystemJsObjectTest, Write)
 {
   jsEngine->Evaluate("_fileSystem.write('foo', 'bar', function(e) {error = e})");
   AdblockPlus::Sleep(50);
   ASSERT_EQ("foo", mockFileSystem->lastWrittenPath);
-  ASSERT_EQ("bar", mockFileSystem->lastWrittenContent);
+  ASSERT_EQ((AdblockPlus::FileSystem::IOBuffer{'b', 'a', 'r'}),
+    mockFileSystem->lastWrittenContent);
   ASSERT_EQ("", jsEngine->Evaluate("error").AsString());
 }
 
 TEST_F(FileSystemJsObjectTest, WriteIllegalArguments)
 {
   ASSERT_ANY_THROW(jsEngine->Evaluate("_fileSystem.write()"));
   ASSERT_ANY_THROW(jsEngine->Evaluate("_fileSystem.write('', '', '')"));
 }
Index: test/Prefs.cpp
===================================================================
--- a/test/Prefs.cpp
+++ b/test/Prefs.cpp
@@ -24,34 +24,30 @@
 
 namespace
 {
   typedef std::shared_ptr<AdblockPlus::FilterEngine> FilterEnginePtr;
 
   class TestFileSystem : public LazyFileSystem
   {
   public:
-    std::string prefsContents;
+    IOBuffer prefsContents;
 
-    std::shared_ptr<std::istream> Read(const std::string& path) const
+    IOBuffer Read(const std::string& path) const
     {
       if (path == "prefs.json" && !prefsContents.empty())
-        return std::shared_ptr<std::istream>(new std::istringstream(prefsContents));
+        return prefsContents;
 
       return LazyFileSystem::Read(path);
     }
 
-    void Write(const std::string& path, std::istream& content)
+    void Write(const std::string& path, const IOBuffer& content)
     {
       if (path == "prefs.json")
-      {
-        std::stringstream ss;
-        ss << content.rdbuf();
-        prefsContents = ss.str();
-      }
+        prefsContents = content;
       else
         LazyFileSystem::Write(path, content);
     }
 
     StatResult Stat(const std::string& path) const
     {
       if (path == "prefs.json")
       {
@@ -139,25 +135,29 @@
     ASSERT_EQ("filters.ini", filterEngine->GetPref("patternsfile").AsString());
     ASSERT_EQ(48, filterEngine->GetPref("patternsbackupinterval").AsInt());
     ASSERT_FALSE(filterEngine->GetPref("subscriptions_autoupdate").AsBool());
   }
 }
 
 TEST_F(PrefsTest, UnknownPrefs)
 {
-  fileSystem->prefsContents = "{\"foobar\":2, \"patternsbackupinterval\": 12}";
+  using IOBuffer = AdblockPlus::FileSystem::IOBuffer;
+  std::string content = "{\"foobar\":2, \"patternsbackupinterval\": 12}";
+  fileSystem->prefsContents = IOBuffer(content.cbegin(), content.cend());
   auto filterEngine = CreateFilterEngine();
   ASSERT_TRUE(filterEngine->GetPref("foobar").IsUndefined());
   ASSERT_EQ(12, filterEngine->GetPref("patternsbackupinterval").AsInt());
 }
 
 TEST_F(PrefsTest, SyntaxFailure)
 {
-  fileSystem->prefsContents = "{\"patternsbackupinterval\": 6, \"foo\"}";
+  using IOBuffer = AdblockPlus::FileSystem::IOBuffer;
+  std::string content = "{\"patternsbackupinterval\": 6, \"foo\"}";
+  fileSystem->prefsContents = IOBuffer(content.cbegin(), content.cend());
   auto filterEngine = CreateFilterEngine();
 
   ASSERT_EQ(24, filterEngine->GetPref("patternsbackupinterval").AsInt());
 }
 
 TEST_F(PrefsTest, PreconfiguredPrefsPreconfigured)
 {
   AdblockPlus::FilterEngine::Prefs preconfiguredPrefs;
