| Index: src/FileSystemJsObject.cpp | 
| diff --git a/src/FileSystemJsObject.cpp b/src/FileSystemJsObject.cpp | 
| index 37e1627c7c1ab0797add282ada968c940f04e1af..feb2358fd17b59954bdff5688f23a7cb51148f8f 100644 | 
| --- a/src/FileSystemJsObject.cpp | 
| +++ b/src/FileSystemJsObject.cpp | 
| @@ -24,6 +24,7 @@ | 
| #include "FileSystemJsObject.h" | 
| #include "JsContext.h" | 
| #include "Utils.h" | 
| +#include "JsError.h" | 
| #include <AdblockPlus/Platform.h> | 
| using namespace AdblockPlus; | 
| @@ -63,6 +64,86 @@ namespace | 
| }); | 
| } | 
| + inline bool CReturnOrLineFeed(char c) | 
| 
 
hub
2017/08/30 21:13:31
nit': I would name this function "IsEndOfLine()"
 
sergei
2017/08/31 10:45:26
I am actually also not glad with the name of this
 
hub
2017/08/31 12:59:43
"End of line" or EOL is often used through the UNI
 
sergei
2017/08/31 13:21:44
agree.
 
 | 
| + { | 
| + return c == 10 || c == 13; | 
| + } | 
| + | 
| + inline StringBuffer::const_iterator SkipCReturnAndLineFeed(StringBuffer::const_iterator ii, StringBuffer::const_iterator end) | 
| 
 
hub
2017/08/30 21:13:30
and this one SkipEndOfLine()
 
 | 
| + { | 
| + while (ii != end && CReturnOrLineFeed(*ii)) | 
| + ++ii; | 
| + return ii; | 
| + } | 
| + | 
| + inline StringBuffer::const_iterator AdvanceUntilCReturnOrLineFeed(StringBuffer::const_iterator ii, StringBuffer::const_iterator end) | 
| 
 
hub
2017/08/30 21:13:31
And this one AdvanceToEndOfLine()
But this is not
 
 | 
| + { | 
| + while (ii != end && !CReturnOrLineFeed(*ii)) | 
| + ++ii; | 
| + return ii; | 
| + } | 
| + | 
| + void ReadFromFileCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| + { | 
| + AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| + AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
| + | 
| + v8::Isolate* isolate = arguments.GetIsolate(); | 
| + if (converted.size() != 3) | 
| + return ThrowExceptionInJS(isolate, "_fileSystem.readFromFile requires 3 parameters"); | 
| + if (!converted[1].IsFunction()) | 
| + return ThrowExceptionInJS(isolate, "Second argument to _fileSystem.readFromFile must be a function (listener callback)"); | 
| + 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; | 
| + | 
| + const JsContext context(*jsEngine); | 
| + | 
| + auto jsValues = jsEngine->TakeJsValues(weakCallback); | 
| + if (!error.empty()) | 
| + { | 
| + jsValues[1].Call(jsEngine->NewValue(error)); | 
| + return; | 
| + } | 
| + | 
| + 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"); | 
| + | 
| + const v8::TryCatch tryCatch; | 
| + | 
| + const auto contentEnd = content.cend(); | 
| + auto stringBegin = SkipCReturnAndLineFeed(content.begin(), contentEnd); | 
| + do | 
| + { | 
| + auto stringEnd = AdvanceUntilCReturnOrLineFeed(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 = SkipCReturnAndLineFeed(stringEnd, contentEnd); | 
| + } while (stringBegin != contentEnd); | 
| + jsValues[1].Call(); | 
| + }); | 
| + } | 
| + | 
| void WriteCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| @@ -198,6 +279,7 @@ namespace | 
| JsValue& FileSystemJsObject::Setup(JsEngine& jsEngine, JsValue& obj) | 
| { | 
| obj.SetProperty("read", jsEngine.NewCallback(::ReadCallback)); | 
| + obj.SetProperty("readFromFile", jsEngine.NewCallback(::ReadFromFileCallback)); | 
| obj.SetProperty("write", jsEngine.NewCallback(::WriteCallback)); | 
| obj.SetProperty("move", jsEngine.NewCallback(::MoveCallback)); | 
| obj.SetProperty("remove", jsEngine.NewCallback(::RemoveCallback)); |