Handle Pdfium errors
... and factor out common code from PdfEditor and PdfRenderer to
PdfUtils.h
Change-Id: If193579d8fccb55a3c2a7e1fa3c935ce410a17c2
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 60e888d..93ff637 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -138,6 +138,7 @@
android/graphics/pdf/PdfDocument.cpp \
android/graphics/pdf/PdfEditor.cpp \
android/graphics/pdf/PdfRenderer.cpp \
+ android/graphics/pdf/PdfUtils.cpp \
android_media_AudioRecord.cpp \
android_media_AudioSystem.cpp \
android_media_AudioTrack.cpp \
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index 21f3c46..b5960dd 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "PdfUtils.h"
+
#include "jni.h"
#include "JNIHelp.h"
@@ -50,79 +52,16 @@
jfieldID bottom;
} gRectClassInfo;
-// Also used in PdfRenderer.cpp
-int sUnmatchedPdfiumInitRequestCount = 0;
-
-static void initializeLibraryIfNeeded() {
- if (sUnmatchedPdfiumInitRequestCount == 0) {
- FPDF_InitLibrary();
- }
- sUnmatchedPdfiumInitRequestCount++;
-}
-
-static void destroyLibraryIfNeeded() {
- sUnmatchedPdfiumInitRequestCount--;
- if (sUnmatchedPdfiumInitRequestCount == 0) {
- FPDF_DestroyLibrary();
- }
-}
-
-static int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
- unsigned long size) {
- const int fd = reinterpret_cast<intptr_t>(param);
- const int readCount = pread(fd, outBuffer, size, position);
- if (readCount < 0) {
- ALOGE("Cannot read from file descriptor. Error:%d", errno);
- return 0;
- }
- return 1;
-}
-
-static jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) {
- initializeLibraryIfNeeded();
-
- FPDF_FILEACCESS loader;
- loader.m_FileLen = size;
- loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
- loader.m_GetBlock = &getBlock;
-
- FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
-
- if (!document) {
- const long error = FPDF_GetLastError();
- switch (error) {
- case FPDF_ERR_PASSWORD:
- case FPDF_ERR_SECURITY: {
- jniThrowExceptionFmt(env, "java/lang/SecurityException",
- "cannot create document. Error: %ld", error);
- } break;
- default: {
- jniThrowExceptionFmt(env, "java/io/IOException",
- "cannot create document. Error: %ld", error);
- } break;
- }
- destroyLibraryIfNeeded();
- return -1;
- }
-
- return reinterpret_cast<jlong>(document);
-}
-
-static void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
- FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
- FPDF_CloseDocument(document);
- destroyLibraryIfNeeded();
-}
-
-static jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
- FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
- return FPDF_GetPageCount(document);
-}
-
static jint nativeRemovePage(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex) {
FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
FPDFPage_Delete(document, pageIndex);
- return FPDF_GetPageCount(document);
+ HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1)
+
+ int pageCount = FPDF_GetPageCount(document);
+ HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1)
+
+ return pageCount;
}
struct PdfToFdWriter : FPDF_FILEWRITE {
@@ -167,8 +106,8 @@
if (!success) {
jniThrowExceptionFmt(env, "java/io/IOException",
"cannot write to fd. Error: %d", errno);
- destroyLibraryIfNeeded();
}
+ HANDLE_PDFIUM_ERROR_STATE(env)
}
static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
@@ -181,6 +120,7 @@
"cannot open page");
return;
}
+ HANDLE_PDFIUM_ERROR_STATE(env);
double width = 0;
double height = 0;
@@ -191,7 +131,11 @@
"cannot get page size");
return;
}
-
+ bool isExceptionPending = forwardPdfiumError(env);
+ if (isExceptionPending) {
+ FPDF_ClosePage(page);
+ return;
+ }
// PDF's coordinate system origin is left-bottom while in graphics it
// is the top-left. So, translate the PDF coordinates to ours.
@@ -208,6 +152,8 @@
SkScalar transformValues[6];
if (!matrix.asAffine(transformValues)) {
+ FPDF_ClosePage(page);
+
jniThrowException(env, "java/lang/IllegalArgumentException",
"transform matrix has perspective. Only affine matrices are allowed.");
return;
@@ -221,8 +167,14 @@
FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
FPDFPage_TransFormWithClip(page, &transform, &clip);
+ isExceptionPending = forwardPdfiumError(env);
+ if (isExceptionPending) {
+ FPDF_ClosePage(page);
+ return;
+ }
FPDF_ClosePage(page);
+ HANDLE_PDFIUM_ERROR_STATE(env);
}
static void nativeGetPageSize(JNIEnv* env, jclass thiz, jlong documentPtr,
@@ -235,6 +187,7 @@
"cannot open page");
return;
}
+ HANDLE_PDFIUM_ERROR_STATE(env);
double width = 0;
double height = 0;
@@ -245,17 +198,17 @@
"cannot get page size");
return;
}
+ bool isExceptionPending = forwardPdfiumError(env);
+ if (isExceptionPending) {
+ FPDF_ClosePage(page);
+ return;
+ }
env->SetIntField(outSize, gPointClassInfo.x, width);
env->SetIntField(outSize, gPointClassInfo.y, height);
FPDF_ClosePage(page);
-}
-
-static jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
- FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
- FPDF_BOOL success = FPDF_VIEWERREF_GetPrintScaling(document);
- return success ? JNI_TRUE : JNI_FALSE;
+ HANDLE_PDFIUM_ERROR_STATE(env);
}
static bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
@@ -268,6 +221,7 @@
"cannot open page");
return false;
}
+ HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false);
float left;
float top;
@@ -277,8 +231,14 @@
const FPDF_BOOL success = (pageBox == PAGE_BOX_MEDIA)
? FPDFPage_GetMediaBox(page, &left, &top, &right, &bottom)
: FPDFPage_GetCropBox(page, &left, &top, &right, &bottom);
+ bool isExceptionPending = forwardPdfiumError(env);
+ if (isExceptionPending) {
+ FPDF_ClosePage(page);
+ return false;
+ }
FPDF_ClosePage(page);
+ HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false);
if (!success) {
return false;
@@ -316,6 +276,7 @@
"cannot open page");
return;
}
+ HANDLE_PDFIUM_ERROR_STATE(env);
const int left = env->GetIntField(box, gRectClassInfo.left);
const int top = env->GetIntField(box, gRectClassInfo.top);
@@ -327,8 +288,14 @@
} else {
FPDFPage_SetCropBox(page, left, top, right, bottom);
}
+ bool isExceptionPending = forwardPdfiumError(env);
+ if (isExceptionPending) {
+ FPDF_ClosePage(page);
+ return;
+ }
FPDF_ClosePage(page);
+ HANDLE_PDFIUM_ERROR_STATE(env);
}
static void nativeSetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 3ef2c027..6e7b6b8 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "PdfUtils.h"
+
#include "jni.h"
#include "JNIHelp.h"
#include "GraphicsJNI.h"
@@ -43,86 +45,28 @@
jfieldID y;
} gPointClassInfo;
-// See PdfEditor.cpp
-extern int sUnmatchedPdfiumInitRequestCount;
-
-static void initializeLibraryIfNeeded() {
- if (sUnmatchedPdfiumInitRequestCount == 0) {
- FPDF_InitLibrary();
- }
- sUnmatchedPdfiumInitRequestCount++;
-}
-
-static void destroyLibraryIfNeeded() {
- sUnmatchedPdfiumInitRequestCount--;
- if (sUnmatchedPdfiumInitRequestCount == 0) {
- FPDF_DestroyLibrary();
- }
-}
-
-static int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
- unsigned long size) {
- const int fd = reinterpret_cast<intptr_t>(param);
- const int readCount = pread(fd, outBuffer, size, position);
- if (readCount < 0) {
- ALOGE("Cannot read from file descriptor. Error:%d", errno);
- return 0;
- }
- return 1;
-}
-
-static jlong nativeCreate(JNIEnv* env, jclass thiz, jint fd, jlong size) {
- initializeLibraryIfNeeded();
-
- FPDF_FILEACCESS loader;
- loader.m_FileLen = size;
- loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
- loader.m_GetBlock = &getBlock;
-
- FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
-
- if (!document) {
- const long error = FPDF_GetLastError();
- switch (error) {
- case FPDF_ERR_PASSWORD:
- case FPDF_ERR_SECURITY: {
- jniThrowExceptionFmt(env, "java/lang/SecurityException",
- "cannot create document. Error: %ld", error);
- } break;
- default: {
- jniThrowExceptionFmt(env, "java/io/IOException",
- "cannot create document. Error: %ld", error);
- } break;
- }
- destroyLibraryIfNeeded();
- return -1;
- }
-
- return reinterpret_cast<jlong>(document);
-}
-
static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPtr,
jint pageIndex, jobject outSize) {
FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
-
if (!page) {
jniThrowException(env, "java/lang/IllegalStateException",
"cannot load page");
return -1;
}
+ HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1)
double width = 0;
double height = 0;
- const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
-
+ int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
if (!result) {
jniThrowException(env, "java/lang/IllegalStateException",
"cannot get page size");
return -1;
}
+ HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1)
env->SetIntField(outSize, gPointClassInfo.x, width);
env->SetIntField(outSize, gPointClassInfo.y, height);
@@ -133,22 +77,7 @@
static void nativeClosePage(JNIEnv* env, jclass thiz, jlong pagePtr) {
FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
FPDF_ClosePage(page);
-}
-
-static void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
- FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
- FPDF_CloseDocument(document);
- destroyLibraryIfNeeded();
-}
-
-static jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
- FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
- return FPDF_GetPageCount(document);
-}
-
-static jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
- FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
- return FPDF_VIEWERREF_GetPrintScaling(document);
+ HANDLE_PDFIUM_ERROR_STATE(env)
}
static void DropContext(void* data) {
@@ -284,7 +213,7 @@
}
static const JNINativeMethod gPdfRenderer_Methods[] = {
- {"nativeCreate", "(IJ)J", (void*) nativeCreate},
+ {"nativeCreate", "(IJ)J", (void*) nativeOpen},
{"nativeClose", "(J)V", (void*) nativeClose},
{"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
{"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
diff --git a/core/jni/android/graphics/pdf/PdfUtils.cpp b/core/jni/android/graphics/pdf/PdfUtils.cpp
new file mode 100644
index 0000000..905a2aa
--- /dev/null
+++ b/core/jni/android/graphics/pdf/PdfUtils.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PdfUtils.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include "fpdfview.h"
+
+#define LOG_TAG "PdfUtils"
+#include <utils/Log.h>
+
+namespace android {
+
+static int sUnmatchedPdfiumInitRequestCount = 0;
+
+int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
+ unsigned long size) {
+ const int fd = reinterpret_cast<intptr_t>(param);
+ const int readCount = pread(fd, outBuffer, size, position);
+ if (readCount < 0) {
+ ALOGE("Cannot read from file descriptor. Error:%d", errno);
+ return 0;
+ }
+ return 1;
+}
+
+// Check if the last pdfium command failed and if so, forward the error to java via an exception. If
+// this function returns true an exception is pending.
+bool forwardPdfiumError(JNIEnv* env) {
+ long error = FPDF_GetLastError();
+ switch (error) {
+ case FPDF_ERR_SUCCESS:
+ return false;
+ case FPDF_ERR_FILE:
+ jniThrowException(env, "java/io/IOException", "file not found or cannot be opened");
+ break;
+ case FPDF_ERR_FORMAT:
+ jniThrowException(env, "java/io/IOException", "file not in PDF format or corrupted");
+ break;
+ case FPDF_ERR_PASSWORD:
+ jniThrowException(env, "java/lang/SecurityException",
+ "password required or incorrect password");
+ break;
+ case FPDF_ERR_SECURITY:
+ jniThrowException(env, "java/lang/SecurityException", "unsupported security scheme");
+ break;
+ case FPDF_ERR_PAGE:
+ jniThrowException(env, "java/io/IOException", "page not found or content error");
+ break;
+#ifdef PDF_ENABLE_XFA
+ case FPDF_ERR_XFALOAD:
+ jniThrowException(env, "java/lang/Exception", "load XFA error");
+ break;
+ case FPDF_ERR_XFALAYOUT:
+ jniThrowException(env, "java/lang/Exception", "layout XFA error");
+ break;
+#endif // PDF_ENABLE_XFA
+ case FPDF_ERR_UNKNOWN:
+ default:
+ jniThrowExceptionFmt(env, "java/lang/Exception", "unknown error %d", error);
+ }
+
+ return true;
+}
+
+static bool initializeLibraryIfNeeded(JNIEnv* env) {
+ if (sUnmatchedPdfiumInitRequestCount == 0) {
+ FPDF_InitLibrary();
+
+ HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false);
+ }
+
+ sUnmatchedPdfiumInitRequestCount++;
+ return true;
+}
+
+static void destroyLibraryIfNeeded(JNIEnv* env, bool handleError) {
+ if (sUnmatchedPdfiumInitRequestCount == 1) {
+ FPDF_DestroyLibrary();
+
+ if (handleError) {
+ HANDLE_PDFIUM_ERROR_STATE(env);
+ }
+ }
+
+ sUnmatchedPdfiumInitRequestCount--;
+}
+
+jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) {
+ bool isInitialized = initializeLibraryIfNeeded(env);
+ if (!isInitialized) {
+ return -1;
+ }
+
+ FPDF_FILEACCESS loader;
+ loader.m_FileLen = size;
+ loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
+ loader.m_GetBlock = &getBlock;
+
+ FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
+ if (!document) {
+ forwardPdfiumError(env);
+ destroyLibraryIfNeeded(env, false);
+ return -1;
+ }
+
+ return reinterpret_cast<jlong>(document);
+}
+
+void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ FPDF_CloseDocument(document);
+ HANDLE_PDFIUM_ERROR_STATE(env)
+
+ destroyLibraryIfNeeded(env, true);
+}
+
+jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ int pageCount = FPDF_GetPageCount(document);
+ HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1);
+
+ return pageCount;
+}
+
+jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+ FPDF_BOOL printScaling = FPDF_VIEWERREF_GetPrintScaling(document);
+ HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false);
+
+ return printScaling ? JNI_TRUE : JNI_FALSE;
+}
+
+};
diff --git a/core/jni/android/graphics/pdf/PdfUtils.h b/core/jni/android/graphics/pdf/PdfUtils.h
new file mode 100644
index 0000000..6e3cebd
--- /dev/null
+++ b/core/jni/android/graphics/pdf/PdfUtils.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PDF_UTILS_H_
+#define PDF_UTILS_H_
+
+#include "jni.h"
+
+namespace android {
+
+int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
+ unsigned long size);
+
+bool forwardPdfiumError(JNIEnv* env);
+
+#define HANDLE_PDFIUM_ERROR_STATE(env) \
+ { \
+ bool isExceptionPending = forwardPdfiumError(env); \
+ if (isExceptionPending) { \
+ return; \
+ } \
+ }
+
+#define HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, retCode) \
+ { \
+ bool isExceptionPending = forwardPdfiumError(env); \
+ if (isExceptionPending) { \
+ return retCode; \
+ } \
+ }
+
+jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size);
+void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr);
+
+jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr);
+jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr);
+
+};
+
+#endif /* PDF_UTILS_H_ */