| Index: src/FileSystemJsObject.cpp | 
| =================================================================== | 
| --- a/src/FileSystemJsObject.cpp | 
| +++ b/src/FileSystemJsObject.cpp | 
| @@ -42,30 +42,35 @@ | 
| return ThrowExceptionInJS(isolate, "_fileSystem.read requires 2 parameters"); | 
| if (!converted[1].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Second argument to _fileSystem.read must be a function"); | 
|  | 
| JsValueList values; | 
| values.push_back(converted[1]); | 
| auto weakCallback = jsEngine->StoreJsValues(values); | 
| std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| -    jsEngine->GetPlatform().GetFileSystem().Read(converted[0].AsString(), | 
| -      [weakJsEngine, weakCallback] | 
| -      (IFileSystem::IOBuffer&& content, const std::string& error) | 
| +    auto fileName = converted[0].AsString(); | 
| +    jsEngine->GetPlatform().WithFileSystem( | 
| +      [weakJsEngine, weakCallback, fileName](IFileSystem& fileSystem) | 
| { | 
| -        auto jsEngine = weakJsEngine.lock(); | 
| -        if (!jsEngine) | 
| -          return; | 
| +        fileSystem.Read(fileName, | 
| +          [weakJsEngine, weakCallback] | 
| +          (IFileSystem::IOBuffer&& content, const std::string& error) | 
| +          { | 
| +            auto jsEngine = weakJsEngine.lock(); | 
| +            if (!jsEngine) | 
| +              return; | 
|  | 
| -        const JsContext context(*jsEngine); | 
| -        auto result = jsEngine->NewObject(); | 
| -        result.SetStringBufferProperty("content", std::move(content)); | 
| -        if (!error.empty()) | 
| -          result.SetProperty("error", error); | 
| -        jsEngine->TakeJsValues(weakCallback)[0].Call(result); | 
| +            const JsContext context(*jsEngine); | 
| +            auto result = jsEngine->NewObject(); | 
| +            result.SetStringBufferProperty("content", std::move(content)); | 
| +            if (!error.empty()) | 
| +              result.SetProperty("error", error); | 
| +            jsEngine->TakeJsValues(weakCallback)[0].Call(result); | 
| +          }); | 
| }); | 
| } | 
|  | 
| inline bool IsEndOfLine(char c) | 
| { | 
| return c == 10 || c == 13; | 
| } | 
|  | 
| @@ -96,57 +101,62 @@ | 
| if (!converted[2].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Third argument to _fileSystem.readFromFile must be a function (done callback)"); | 
|  | 
| JsValueList values; | 
| values.push_back(converted[1]); | 
| values.push_back(converted[2]); | 
| auto weakCallback = jsEngine->StoreJsValues(values); | 
| std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| -    jsEngine->GetPlatform().GetFileSystem().Read(converted[0].AsString(), | 
| -      [weakJsEngine, weakCallback] | 
| -    (IFileSystem::IOBuffer&& content, const std::string& error) | 
| -    { | 
| -      auto jsEngine = weakJsEngine.lock(); | 
| -      if (!jsEngine) | 
| -        return; | 
| +    auto fileName = converted[0].AsString(); | 
| +    jsEngine->GetPlatform().WithFileSystem( | 
| +      [weakJsEngine, weakCallback, fileName](IFileSystem& fileSystem) | 
| +      { | 
| +        fileSystem.Read(fileName, | 
| +          [weakJsEngine, weakCallback] | 
| +          (IFileSystem::IOBuffer&& content, const std::string& error) | 
| +          { | 
| +            auto jsEngine = weakJsEngine.lock(); | 
| +            if (!jsEngine) | 
| +              return; | 
|  | 
| -      const JsContext context(*jsEngine); | 
| +            const JsContext context(*jsEngine); | 
|  | 
| -      auto jsValues = jsEngine->TakeJsValues(weakCallback); | 
| -      if (!error.empty()) | 
| -      { | 
| -        jsValues[1].Call(jsEngine->NewValue(error)); | 
| -        return; | 
| -      } | 
| +            auto jsValues = jsEngine->TakeJsValues(weakCallback); | 
| +            if (!error.empty()) | 
| +            { | 
| +              jsValues[1].Call(jsEngine->NewValue(error)); | 
| +              return; | 
| +            } | 
|  | 
| -      auto processFunc = jsValues[0].UnwrapValue().As<v8::Function>(); | 
| +            auto processFunc = jsValues[0].UnwrapValue().As<v8::Function>(); | 
|  | 
| -      auto globalContext = context.GetV8Context()->Global(); | 
| -      if (!globalContext->IsObject()) | 
| -        throw std::runtime_error("`this` pointer has to be an object"); | 
| +            auto globalContext = context.GetV8Context()->Global(); | 
| +            if (!globalContext->IsObject()) | 
| +              throw std::runtime_error("`this` pointer has to be an object"); | 
|  | 
| -      const v8::TryCatch tryCatch; | 
| +            const v8::TryCatch tryCatch; | 
|  | 
| -      const auto contentEnd = content.cend(); | 
| -      auto stringBegin = SkipEndOfLine(content.begin(), contentEnd); | 
| -      do | 
| -      { | 
| -        auto stringEnd = AdvanceToEndOfLine(stringBegin, contentEnd); | 
| -        auto jsLine = Utils::StringBufferToV8String(jsEngine->GetIsolate(), StringBuffer(stringBegin, stringEnd)).As<v8::Value>(); | 
| -        processFunc->Call(globalContext, 1, &jsLine); | 
| -        if (tryCatch.HasCaught()) | 
| -        { | 
| -          jsValues[1].Call(jsEngine->NewValue(JsError::ExceptionToString(tryCatch.Exception(), tryCatch.Message()))); | 
| -          return; | 
| -        } | 
| -        stringBegin = SkipEndOfLine(stringEnd, contentEnd); | 
| -      } while (stringBegin != contentEnd); | 
| -      jsValues[1].Call(); | 
| -    }); | 
| +            const auto contentEnd = content.cend(); | 
| +            auto stringBegin = SkipEndOfLine(content.begin(), contentEnd); | 
| +            do | 
| +            { | 
| +              auto stringEnd = AdvanceToEndOfLine(stringBegin, contentEnd); | 
| +              auto jsLine = Utils::StringBufferToV8String(jsEngine->GetIsolate(), StringBuffer(stringBegin, stringEnd)).As<v8::Value>(); | 
| +              processFunc->Call(globalContext, 1, &jsLine); | 
| +              if (tryCatch.HasCaught()) | 
| +              { | 
| +                jsValues[1].Call(jsEngine->NewValue(JsError::ExceptionToString(tryCatch.Exception(), tryCatch.Message()))); | 
| +                return; | 
| +              } | 
| +              stringBegin = SkipEndOfLine(stringEnd, contentEnd); | 
| +            } while (stringBegin != contentEnd); | 
| +            jsValues[1].Call(); | 
| +          }); | 
| +      }); | 
| } | 
|  | 
| void WriteCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
|  | 
| v8::Isolate* isolate = arguments.GetIsolate(); | 
| @@ -155,29 +165,33 @@ | 
| if (!converted[2].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Third argument to _fileSystem.write must be a function"); | 
|  | 
| JsValueList values; | 
| values.push_back(converted[2]); | 
| auto weakCallback = jsEngine->StoreJsValues(values); | 
| std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| auto content = converted[1].AsStringBuffer(); | 
| -    jsEngine->GetPlatform().GetFileSystem().Write(converted[0].AsString(), | 
| -      content, | 
| -      [weakJsEngine, weakCallback](const std::string& error) | 
| +    auto fileName = converted[0].AsString(); | 
| +    jsEngine->GetPlatform().WithFileSystem( | 
| +      [weakJsEngine, weakCallback, fileName, content](IFileSystem& fileSystem) | 
| { | 
| -        auto jsEngine = weakJsEngine.lock(); | 
| -        if (!jsEngine) | 
| -          return; | 
| +        fileSystem.Write(fileName, content, | 
| +          [weakJsEngine, weakCallback](const std::string& error) | 
| +          { | 
| +            auto jsEngine = weakJsEngine.lock(); | 
| +            if (!jsEngine) | 
| +              return; | 
|  | 
| -        const JsContext context(*jsEngine); | 
| -        JsValueList params; | 
| -        if (!error.empty()) | 
| -          params.push_back(jsEngine->NewValue(error)); | 
| -        jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +            const JsContext context(*jsEngine); | 
| +            JsValueList params; | 
| +            if (!error.empty()) | 
| +              params.push_back(jsEngine->NewValue(error)); | 
| +            jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +          }); | 
| }); | 
| } | 
|  | 
| void MoveCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
|  | 
| @@ -186,29 +200,34 @@ | 
| return ThrowExceptionInJS(isolate, "_fileSystem.move requires 3 parameters"); | 
| if (!converted[2].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Third argument to _fileSystem.move must be a function"); | 
|  | 
| JsValueList values; | 
| values.push_back(converted[2]); | 
| auto weakCallback = jsEngine->StoreJsValues(values); | 
| std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| -    jsEngine->GetPlatform().GetFileSystem().Move(converted[0].AsString(), | 
| -      converted[1].AsString(), | 
| -      [weakJsEngine, weakCallback](const std::string& error) | 
| +    auto from = converted[0].AsString(); | 
| +    auto to = converted[1].AsString(); | 
| +    jsEngine->GetPlatform().WithFileSystem( | 
| +      [weakJsEngine, weakCallback, from, to](IFileSystem& fileSystem) | 
| { | 
| -        auto jsEngine = weakJsEngine.lock(); | 
| -        if (!jsEngine) | 
| -          return; | 
| +        fileSystem.Move(from, to, | 
| +          [weakJsEngine, weakCallback](const std::string& error) | 
| +          { | 
| +            auto jsEngine = weakJsEngine.lock(); | 
| +            if (!jsEngine) | 
| +              return; | 
|  | 
| -        const JsContext context(*jsEngine); | 
| -        JsValueList params; | 
| -        if (!error.empty()) | 
| -          params.push_back(jsEngine->NewValue(error)); | 
| -        jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +            const JsContext context(*jsEngine); | 
| +            JsValueList params; | 
| +            if (!error.empty()) | 
| +              params.push_back(jsEngine->NewValue(error)); | 
| +            jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +          }); | 
| }); | 
| } | 
|  | 
| void RemoveCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
|  | 
| @@ -217,28 +236,33 @@ | 
| return ThrowExceptionInJS(isolate, "_fileSystem.remove requires 2 parameters"); | 
| if (!converted[1].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Second argument to _fileSystem.remove must be a function"); | 
|  | 
| JsValueList values; | 
| values.push_back(converted[1]); | 
| auto weakCallback = jsEngine->StoreJsValues(values); | 
| std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| -    jsEngine->GetPlatform().GetFileSystem().Remove(converted[0].AsString(), | 
| -      [weakJsEngine, weakCallback](const std::string& error) | 
| +    auto fileName = converted[0].AsString(); | 
| +    jsEngine->GetPlatform().WithFileSystem( | 
| +      [weakJsEngine, weakCallback, fileName](IFileSystem& fileSystem) | 
| { | 
| -        auto jsEngine = weakJsEngine.lock(); | 
| -        if (!jsEngine) | 
| -          return; | 
| +        fileSystem.Remove(fileName, | 
| +          [weakJsEngine, weakCallback](const std::string& error) | 
| +          { | 
| +            auto jsEngine = weakJsEngine.lock(); | 
| +            if (!jsEngine) | 
| +              return; | 
|  | 
| -        const JsContext context(*jsEngine); | 
| -        JsValueList params; | 
| -        if (!error.empty()) | 
| -          params.push_back(jsEngine->NewValue(error)); | 
| -        jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +            const JsContext context(*jsEngine); | 
| +            JsValueList params; | 
| +            if (!error.empty()) | 
| +              params.push_back(jsEngine->NewValue(error)); | 
| +            jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +          }); | 
| }); | 
| } | 
|  | 
| void StatCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
|  | 
| @@ -247,35 +271,40 @@ | 
| return ThrowExceptionInJS(isolate, "_fileSystem.stat requires 2 parameters"); | 
| if (!converted[1].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Second argument to _fileSystem.stat must be a function"); | 
|  | 
| JsValueList values; | 
| values.push_back(converted[1]); | 
| auto weakCallback = jsEngine->StoreJsValues(values); | 
| std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| -    jsEngine->GetPlatform().GetFileSystem().Stat(converted[0].AsString(), | 
| -      [weakJsEngine, weakCallback] | 
| -      (const IFileSystem::StatResult& statResult, const std::string& error) | 
| +    auto fileName = converted[0].AsString(); | 
| +    jsEngine->GetPlatform().WithFileSystem( | 
| +      [weakJsEngine, weakCallback, fileName](IFileSystem& fileSystem) | 
| { | 
| -        auto jsEngine = weakJsEngine.lock(); | 
| -        if (!jsEngine) | 
| -          return; | 
| +        fileSystem.Stat(fileName, | 
| +           [weakJsEngine, weakCallback] | 
| +           (const IFileSystem::StatResult& statResult, const std::string& error) | 
| +           { | 
| +             auto jsEngine = weakJsEngine.lock(); | 
| +             if (!jsEngine) | 
| +               return; | 
|  | 
| -        const JsContext context(*jsEngine); | 
| -        auto result = jsEngine->NewObject(); | 
| +             const JsContext context(*jsEngine); | 
| +             auto result = jsEngine->NewObject(); | 
|  | 
| -        result.SetProperty("exists", statResult.exists); | 
| -        result.SetProperty("lastModified", statResult.lastModified); | 
| -        if (!error.empty()) | 
| -          result.SetProperty("error", error); | 
| +             result.SetProperty("exists", statResult.exists); | 
| +             result.SetProperty("lastModified", statResult.lastModified); | 
| +             if (!error.empty()) | 
| +               result.SetProperty("error", error); | 
|  | 
| -        JsValueList params; | 
| -        params.push_back(result); | 
| -        jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +             JsValueList params; | 
| +             params.push_back(result); | 
| +             jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +           }); | 
| }); | 
| } | 
| } | 
|  | 
|  | 
| JsValue& FileSystemJsObject::Setup(JsEngine& jsEngine, JsValue& obj) | 
| { | 
| obj.SetProperty("read", jsEngine.NewCallback(::ReadCallback)); | 
|  |