Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: libadblockplus-android/jni/JniFileSystem.cpp

Issue 29424615: Issue 4231 - Fix unstable FilterEngineTest.testSetRemoveFilterChangeCallback (Closed)
Patch Set: changed impl for reading file as bytes array, modified test. AndroidFileSystem now does not resolveā€¦ Created May 29, 2017, 11:26 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: libadblockplus-android/jni/JniFileSystem.cpp
diff --git a/libadblockplus-android/jni/JniFileSystem.cpp b/libadblockplus-android/jni/JniFileSystem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f87e05752683b8331851dd0a2045061e4e48f574
--- /dev/null
+++ b/libadblockplus-android/jni/JniFileSystem.cpp
@@ -0,0 +1,228 @@
+/*
+ * This file is part of Adblock Plus <https://adblockplus.org/>,
+ * Copyright (C) 2006-2017 eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * 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 "JniCallbacks.h"
+#include "AdblockPlus/FileSystem.h"
+#include "Utils.h"
+#include <istream>
+#include <streambuf>
+
+class RuntimeErrorWithErrno : public std::runtime_error
+{
+public:
+ explicit RuntimeErrorWithErrno(const std::string& message)
+ : std::runtime_error(message + " (" + strerror(errno) + ")")
+ {
+ }
+};
+
+struct membuf: std::streambuf {
+ membuf(char const* base, size_t size) {
+ char* p(const_cast<char*>(base));
+ this->setg(p, p, p + size);
+ }
+};
+
+struct imemstream: virtual membuf, std::istream {
+ imemstream(char const* base, size_t size)
+ : membuf(base, size)
+ , std::istream(static_cast<std::streambuf*>(this)) {
+ }
+};
sergei 2017/08/07 12:50:00 All these things should be in the anonymous namesp
+
+// precached in JNI_OnLoad and released in JNI_OnUnload
+JniGlobalReference<jclass>* statResultClass;
+jmethodID existsMethod;
+jmethodID isDirectoryMethod;
+jmethodID isFileMethod;
+jmethodID getLastModifiedMethod;
+
+void JniFileSystem_OnLoad(JavaVM* vm, JNIEnv* env, void* reserved)
+{
+ statResultClass = new JniGlobalReference<jclass>(env, env->FindClass(PKG("FileSystem$StatResult")));
+ existsMethod = env->GetMethodID(statResultClass->Get(), "exists", "()Z");
+ isDirectoryMethod = env->GetMethodID(statResultClass->Get(), "isDirectory", "()Z");
+ isFileMethod = env->GetMethodID(statResultClass->Get(), "isFile", "()Z");
+ getLastModifiedMethod = env->GetMethodID(statResultClass->Get(), "getLastModified", "()J");
+}
+
+void JniFileSystem_OnUnload(JavaVM* vm, JNIEnv* env, void* reserved)
+{
+ if (statResultClass)
+ {
+ delete statResultClass;
+ statResultClass = NULL;
sergei 2017/08/07 12:50:00 nullptr?
+ }
+}
+
+static jlong JNICALL JniCtor(JNIEnv* env, jclass clazz, jobject callbackObject)
sergei 2017/08/07 12:49:59 I think that it should be done a little bit differ
+{
+ try
+ {
+ return JniPtrToLong(new AdblockPlus::FileSystemPtr(new JniFileSystemCallback(env, callbackObject)));
+ }
+ CATCH_THROW_AND_RETURN(env, 0)
+}
+
+static void JNICALL JniDtor(JNIEnv* env, jclass clazz, jlong ptr)
+{
+ delete JniLongToTypePtr<AdblockPlus::FileSystemPtr>(ptr);
+}
+
+JniFileSystemCallback::JniFileSystemCallback(JNIEnv* env, jobject callbackObject)
+ : JniCallbackBase(env, callbackObject)
+{
+}
+
+std::shared_ptr<std::istream> JniFileSystemCallback::Read(const std::string& path) const
+{
+ JNIEnvAcquire env(GetJavaVM());
+
+ jmethodID method = env->GetMethodID(
+ *JniLocalReference<jclass>(*env, env->GetObjectClass(GetCallbackObject())),
+ "read",
+ "(Ljava/lang/String;)[B");
+
+ JniLocalReference<jstring> jPath(*env, env->NewStringUTF(path.c_str()));
+ jbyteArray jData = (jbyteArray)env->CallObjectMethod(GetCallbackObject(), method, *jPath);
+ if (CheckAndLogJavaException(*env))
+ throw new RuntimeErrorWithErrno("Failed to open file (File not found)");
+
+ int dataLength = env->GetArrayLength(jData);
+ char* cData = new char[dataLength];
+ env->GetByteArrayRegion(jData, 0, dataLength, reinterpret_cast<jbyte*>(cData));
+
+ std::shared_ptr<std::istream> cSharedStream(new imemstream(cData, dataLength));
+ return cSharedStream;
+}
+
+void JniFileSystemCallback::Write(const std::string& path, std::shared_ptr<std::istream> dataStreamPtr)
+{
+ JNIEnvAcquire env(GetJavaVM());
+
+ jmethodID method = env->GetMethodID(
+ *JniLocalReference<jclass>(*env, env->GetObjectClass(GetCallbackObject())),
+ "write",
+ "(Ljava/lang/String;[B)V");
+
+ JniLocalReference<jstring> jPath(*env, env->NewStringUTF(path.c_str()));
+
+ // read all the data from the stream into buffer (no appropriate way to pass streams over JNI)
+ std::istream* dataStream = dataStreamPtr.get();
+ dataStream->seekg(0, std::ios::end);
+ int dataLength = dataStream->tellg();
+ char* cData = new char[dataLength];
+ dataStream->seekg(0, std::ios::beg);
+ dataStream->read(cData, dataLength);
+
+ jbyteArray jData = env->NewByteArray(dataLength);
+ env->SetByteArrayRegion(jData, 0, dataLength, reinterpret_cast<jbyte*>(cData));
+
+ env->CallVoidMethod(GetCallbackObject(), method, *jPath, jData);
+ CheckAndLogJavaException(*env);
+ delete[] cData;
+}
+
+void JniFileSystemCallback::Move(const std::string& fromPath, const std::string& toPath)
+{
+ JNIEnvAcquire env(GetJavaVM());
+
+ jmethodID method = env->GetMethodID(
+ *JniLocalReference<jclass>(*env, env->GetObjectClass(GetCallbackObject())),
+ "move",
+ "(Ljava/lang/String;Ljava/lang/String;)V");
+
+ JniLocalReference<jstring> jFromPath(*env, env->NewStringUTF(fromPath.c_str()));
+ JniLocalReference<jstring> jToPath(*env, env->NewStringUTF(toPath.c_str()));
+
+ env->CallVoidMethod(GetCallbackObject(), method, *jFromPath, *jToPath);
+ CheckAndLogJavaException(*env);
+}
+
+void JniFileSystemCallback::Remove(const std::string& path)
+{
+ JNIEnvAcquire env(GetJavaVM());
+
+ jmethodID method = env->GetMethodID(
+ *JniLocalReference<jclass>(*env, env->GetObjectClass(GetCallbackObject())),
+ "remove",
+ "(Ljava/lang/String;)V");
+
+ JniLocalReference<jstring> jPath(*env, env->NewStringUTF(path.c_str()));
+
+ env->CallVoidMethod(GetCallbackObject(), method, *jPath);
+ CheckAndLogJavaException(*env);
+}
+
+AdblockPlus::FileSystem::StatResult JniFileSystemCallback::Stat(const std::string& path) const
+{
+ JNIEnvAcquire env(GetJavaVM());
+
+ jmethodID method = env->GetMethodID(
+ *JniLocalReference<jclass>(*env, env->GetObjectClass(GetCallbackObject())),
+ "stat",
+ "(Ljava/lang/String;)" TYP("FileSystem$StatResult"));
+
+ JniLocalReference<jstring> jPath(*env, env->NewStringUTF(path.c_str()));
+
+ jobject jStatResult = env->CallObjectMethod(GetCallbackObject(), method, *jPath);
+ CheckAndLogJavaException(*env);
+
+ AdblockPlus::FileSystem::StatResult statResult;
+
+ statResult.exists = env->CallBooleanMethod(jStatResult, existsMethod) ? JNI_TRUE : JNI_FALSE;
+ CheckAndLogJavaException(*env);
+
+ statResult.isDirectory = env->CallBooleanMethod(jStatResult, isDirectoryMethod) ? JNI_TRUE : JNI_FALSE;
+ CheckAndLogJavaException(*env);
+
+ statResult.isFile = env->CallBooleanMethod(jStatResult, isFileMethod) ? JNI_TRUE : JNI_FALSE;
+ CheckAndLogJavaException(*env);
+
+ statResult.lastModified = env->CallLongMethod(jStatResult, getLastModifiedMethod);
+ CheckAndLogJavaException(*env);
+
+ return statResult;
+}
+
+std::string JniFileSystemCallback::Resolve(const std::string& path) const
+{
+ JNIEnvAcquire env(GetJavaVM());
+
+ jmethodID method = env->GetMethodID(
+ *JniLocalReference<jclass>(*env, env->GetObjectClass(GetCallbackObject())),
+ "resolve",
+ "(Ljava/lang/String;)Ljava/lang/String;");
+
+ JniLocalReference<jstring> jPath(*env, env->NewStringUTF(path.c_str()));
+
+ jstring jRet = (jstring)env->CallObjectMethod(GetCallbackObject(), method, *jPath);
+ CheckAndLogJavaException(*env);
+
+ return JniJavaToStdString(*env, jRet);
+}
+
+static JNINativeMethod methods[] =
+{
+ { (char*)"ctor", (char*)"(Ljava/lang/Object;)J", (void*)JniCtor },
+ { (char*)"dtor", (char*)"(J)V", (void*)JniDtor }
+};
+
+extern "C" JNIEXPORT void JNICALL Java_org_adblockplus_libadblockplus_FileSystem_registerNatives(JNIEnv *env, jclass clazz)
+{
+ env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0]));
+}

Powered by Google App Engine
This is Rietveld