Skip to content

Commit

Permalink
adding content filter error handler based on previous additions to th…
Browse files Browse the repository at this point in the history
…e develop branch
  • Loading branch information
Aferdita Muriqi committed Feb 16, 2017
1 parent 7fe6413 commit 91546e2
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 0 deletions.
45 changes: 45 additions & 0 deletions Platform/Android/epub3/src/main/jni/epub3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include <ePub3/archive.h>
#include <ePub3/container.h>
#include <ePub3/filter.h>
#include <ePub3/initialization.h>
#include <ePub3/utilities/error_handler.h>

Expand Down Expand Up @@ -70,6 +71,9 @@ static const char *javaEPub3_appendBytesToBufferSignature = "(Ljava/nio/ByteBuff
static const char *javaEPub3_handleSdkErrorMethodName = "handleSdkError";
static const char *javaEPub3_handleSdkErrorSignature = "(Ljava/lang/String;Z)Z";

static const char *javaEPub3_handleContentFilterErrorMethodName = "handleContentFilterError";
static const char *javaEPub3_handleContentFilterErrorSignature = "(Ljava/lang/String;JLjava/lang/String;)V";


/*
* Exported variables
Expand All @@ -95,6 +99,11 @@ jmethodID createManifestItem_ID;
jmethodID addManifestItemToList_ID;


// Global variable to store the current Java virtual machine.
// This will be needed by the ContentFilterErrorHandler() function.
JavaVM *g_vm = NULL;


/*
* Internal variables
**************************************************/
Expand All @@ -113,6 +122,7 @@ static jmethodID appendBytesToBuffer_ID;
static jmethodID handleSdkError_ID;
static jmethodID contentFiltersRegistrationHandler_Run_ID;

static jmethodID handleContentFilterError_ID;

/*
* Exported functions
Expand Down Expand Up @@ -192,6 +202,10 @@ jboolean javaEPub3_handleSdkError(JNIEnv *env, jstring message, jboolean isSever
return b;
}

void javaEPub3_handleContentFilterError(JNIEnv *env, jstring filterId, jlong errorCode, jstring message) {
env->CallStaticVoidMethod(javaEPub3Class, handleContentFilterError_ID, filterId, errorCode, message);
}

/*
* Internal functions
**************************************************/
Expand All @@ -213,6 +227,8 @@ static int onLoad_cacheJavaElements_epub3(JNIEnv *env) {
javaEPub3_appendBytesToBufferMethodName, javaEPub3_appendBytesToBufferSignature, ONLOAD_ERROR);
INIT_STATIC_METHOD_ID_RETVAL(handleSdkError_ID, javaEPub3Class, javaEPub3ClassName,
javaEPub3_handleSdkErrorMethodName, javaEPub3_handleSdkErrorSignature, ONLOAD_ERROR);
INIT_STATIC_METHOD_ID_RETVAL(handleContentFilterError_ID, javaEPub3Class, javaEPub3ClassName,
javaEPub3_handleContentFilterErrorMethodName, javaEPub3_handleContentFilterErrorSignature, ONLOAD_ERROR);
// Return JNI_VERSION for OK, if not one of the lines above already returned ONLOAD_ERROR
return JNI_VERSION;
}
Expand Down Expand Up @@ -240,6 +256,30 @@ static bool LauncherErrorHandler(const ePub3::error_details& err)
//return ePub3::DefaultErrorHandler(err);
}

/**
* Callback to be invoked when any ContentFilter has an error.
*/

static void ContentFilterErrorHandler(const std::string &filterId, unsigned int errorCode, const std::string &message)
{
// Making sure that we have the right JNI environment pointer for every thread.
// This function may be called in different threads, and you must have the right
// JNI environment pointer for the current thread, otherwise it will crash the app.
JNIEnv *env;
if (g_vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK) {
LOGE("ContentFilterErrorHandler: failed to get environment. VM doesn't support JNI version 1.6");
return;
}

jstring jFilterId = env->NewStringUTF(filterId.c_str());
jstring jMessage = env->NewStringUTF(message.c_str());

javaEPub3_handleContentFilterError(env, jFilterId, (jlong)errorCode, jMessage);

env->DeleteLocalRef(jFilterId);
env->DeleteLocalRef(jMessage);
}

/**
* Initializes the Readium SDK.
*/
Expand All @@ -252,6 +292,9 @@ static void initializeReadiumSDK(JNIEnv* env)
ePub3::ErrorHandlerFn launcherErrorHandler = LauncherErrorHandler;
ePub3::SetErrorHandler(launcherErrorHandler);

ePub3::ContentFilterErrorHandlerFn contentFilterErrorHandler = ContentFilterErrorHandler;
ePub3::ContentFilter::ResetContentFilterErrorHandler(contentFilterErrorHandler);

ePub3::InitializeSdk();
ePub3::PopulateFilterManager();

Expand All @@ -273,6 +316,8 @@ static void initializeReadiumSDK(JNIEnv* env)
*/
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
g_vm = vm;

// Get the JNI Environment to be able to initialize the cached the java elements
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION) != JNI_OK) {
Expand Down
2 changes: 2 additions & 0 deletions Platform/Android/epub3/src/main/jni/epub3.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ void javaEPub3_appendBytesToBuffer(JNIEnv *env, jobject buffer, jbyteArray data)

jboolean javaEPub3_handleSdkError(JNIEnv *env, jstring message, jboolean isSevereEpubError);

void javaEPub3_handleContentFilterError(JNIEnv *env, jstring filterId, jlong errorCode, jstring message);

/*
* JNI functions
**************************************************/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2015 Readium Foundation and/or its licensees. All rights reserved.
//
// This program 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.
//
// Licensed under Gnu Affero General Public License Version 3 (provided, notwithstanding this notice,
// Readium Foundation reserves the right to license this material under a different separate license,
// and if you have done so, the terms of that separate license control and the following references
// to GPL do not apply).
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU
// Affero General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version. You should have received a copy of the GNU
// Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.


package org.readium.sdk.android;

public interface ContentFilterErrorHandler {
void handleContentFilterError(String filterId, long errorCode, String message);
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,16 @@ private static boolean handleSdkError(String message, boolean isSevereEpubError)
// never throws an exception
return true;
}

private static ContentFilterErrorHandler m_contentFilterErrorHandler = null;

public static void setContentFilterErrorHandler(ContentFilterErrorHandler handler) {
m_contentFilterErrorHandler = handler;
}

private static void handleContentFilterError(String filterId, long errorCode, String message) {
if (m_contentFilterErrorHandler != null) {
m_contentFilterErrorHandler.handleContentFilterError(filterId, errorCode, message);
}
}
}
4 changes: 4 additions & 0 deletions ePub3/ePub/PassThroughFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ void *PassThroughFilter::FilterData(FilterContext *context, void *data, size_t l

if (!byteStream->IsOpen())
{
HandleContentFilterError(
std::string(PASS_THROUGH_FILTER_ID),
ContentFilterError::InputStreamCannotBeOpened,
std::string("Input ByteStream is not opened"));
return nullptr;
}

Expand Down
3 changes: 3 additions & 0 deletions ePub3/ePub/PassThroughFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include <cstring>
#import <ePub3/utilities/byte_stream.h>

#define PASS_THROUGH_FILTER_ID "3439DA53-2559-400D-8231-981ABA6A85B4"


EPUB3_BEGIN_NAMESPACE


Expand Down
29 changes: 29 additions & 0 deletions ePub3/ePub/filter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// filter.cpp
// ePub3
//
// Created by Nelson Leme on 5/28/15.
// Copyright (c) 2015 The Readium Foundation and contributors. All rights reserved.
//
// This program 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.
//
// Licensed under Gnu Affero General Public License Version 3 (provided, notwithstanding this notice,
// Readium Foundation reserves the right to license this material under a different separate license,
// and if you have done so, the terms of that separate license control and the following references
// to GPL do not apply).
//
// This program is free software: you can redistribute it and/or modify it under the terms of the GNU
// Affero General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version. You should have received a copy of the GNU
// Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.


#include <stdio.h>
#include "filter.h"

EPUB3_BEGIN_NAMESPACE

ContentFilterErrorHandlerFn ContentFilter::s_contentFilterErrorHandler = ContentFilter::DefaultContentFilterErrorHandler;

EPUB3_END_NAMESPACE
75 changes: 75 additions & 0 deletions ePub3/ePub/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ typedef std::shared_ptr<Package> PackagePtr;
class ContentFilter;
typedef std::shared_ptr<ContentFilter> ContentFilterPtr;

enum class ContentFilterError : unsigned int
{
GenericError = 0,
InputStreamCannotBeOpened,
OutputStreamCannotBeSought,
CorruptedResource,
NoLicenseForDecryption,
NotEnoughBytesAvailable
};

typedef std::function<void(const std::string &, unsigned int code, const std::string &)> ContentFilterErrorHandlerFn;


// -------------------------------------------------------------------------------------------

class ByteRange
Expand Down Expand Up @@ -287,6 +300,10 @@ class ContentFilter
/// No default constructor.
ContentFilter() _DELETED_;

static void DefaultContentFilterErrorHandler(const std::string &filterId, unsigned int code, const std::string &message) { };

static ContentFilterErrorHandlerFn s_contentFilterErrorHandler;

public:
///
/// Copy constructor.
Expand Down Expand Up @@ -364,6 +381,23 @@ class ContentFilter
*/
virtual void *FilterData(FilterContext* context, void *data, size_t len, size_t *outputLen) = 0;

/**
Reset the ContentFilteErrorHandler function.
Any app that is using the Readium SDK (and its associated ContentFilter classes) may
want to set up its own ContentFilterErrorHandler function. This way, the app can be notified
when there is an error in the processing done by the ContentFilter objects. Notice that,
unless this function is called and reset to something meaningful, the default
ContentFilterErrorHandler function is called, which will simply ignore any errors from the
ContentFilter.
@param contentFilterErrorHandler A new ContentFilterErrorHandler function
*/
static void ResetContentFilterErrorHandler(ContentFilterErrorHandlerFn contentFilterErrorHandler)
{
s_contentFilterErrorHandler = contentFilterErrorHandler;
}

protected:
TypeSnifferFn _sniffer;

Expand All @@ -387,6 +421,47 @@ class ContentFilter
@result An object containing per-item data, or nullptr.
*/
virtual FilterContext *InnerMakeFilterContext(ConstManifestItemPtr item) const { return nullptr; }

/**
Report an error during the processing done by a ContentFilter.
When a ContentFilter is processing a sequence of bytes, it may reach an error. In that
case, the ContentFilter will want to report to the underlying app that something went
wrong, so that it can report that to the user. The two overloads of HandleContentFilterError(),
below, do exactly that: they allow an app to receive the error description (as parameters)
whenever an error happens in a given ContentFilter.
Notice that the first parameter of both overloads is the filterId. The filterId is a UUID (or
GUID) that identifies uniquely a different class of ContentFilter. This way, no matter how many
ContentFilter classes are created all over, there will be a unique way to identify each one of
them, and any app that uses the Readium SDK will not run the risk of mistaking one class of
ContentFilter by another.
@param filterId A UUID (or GUID) that will uniquely identify a given class of ContentFilter.
@param error One of the possible values of the ContentFilterError enumeration.
@param message An optional text message, containing whatever the ContentFilter wants to say.
*/
static void HandleContentFilterError(const std::string &filterId, ContentFilterError error, const std::string &message)
{
HandleContentFilterError(filterId, (unsigned int)error, message);
}

/**
Report an error during the processing done by a ContentFilter.
This overload of HandleContentFilterError does exactly the same as the previous overload, with
one difference: the caller can pass an unsigned integer for error code, instead of the
ContentFilterError enumeration. The reason is that different people writing ContentFilter classes
may decide to use their own error codes for things.
@param filterId A UUID (or GUID) that will uniquely identify a given class of ContentFilter.
@param error An unsigned integer that corresponds to an error code.
@param message An optional text message, containing whatever the ContentFilter wants to say.
*/
static void HandleContentFilterError(const std::string &filterId, unsigned int errorCode, const std::string &message)
{
s_contentFilterErrorHandler(filterId, errorCode, message);
}

};

Expand Down

3 comments on commit 91546e2

@clebeaupin
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feature looks very interesting. Could you create a pull request to the readium sdk project ?

@aferditamuriqi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes will do that

@danielweck
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be clear, this feature was originally proposed for inclusion in ReadiumSDK by Bluefire's Nelson Leme, in this Pull Request: readium#239
I am now tasked to adapt the PR code as necessary, in order to merge cleanly into master / release 0.27 (via develop, of course).

Please sign in to comment.