1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "PdfUtils.h" 18 19#include "jni.h" 20#include "JNIHelp.h" 21 22#include "fpdfview.h" 23 24#define LOG_TAG "PdfUtils" 25#include <utils/Log.h> 26 27namespace android { 28 29static int sUnmatchedPdfiumInitRequestCount = 0; 30 31int getBlock(void* param, unsigned long position, unsigned char* outBuffer, 32 unsigned long size) { 33 const int fd = reinterpret_cast<intptr_t>(param); 34 const int readCount = pread(fd, outBuffer, size, position); 35 if (readCount < 0) { 36 ALOGE("Cannot read from file descriptor. Error:%d", errno); 37 return 0; 38 } 39 return 1; 40} 41 42// Check if the last pdfium command failed and if so, forward the error to java via an exception. If 43// this function returns true an exception is pending. 44bool forwardPdfiumError(JNIEnv* env) { 45 long error = FPDF_GetLastError(); 46 switch (error) { 47 case FPDF_ERR_SUCCESS: 48 return false; 49 case FPDF_ERR_FILE: 50 jniThrowException(env, "java/io/IOException", "file not found or cannot be opened"); 51 break; 52 case FPDF_ERR_FORMAT: 53 jniThrowException(env, "java/io/IOException", "file not in PDF format or corrupted"); 54 break; 55 case FPDF_ERR_PASSWORD: 56 jniThrowException(env, "java/lang/SecurityException", 57 "password required or incorrect password"); 58 break; 59 case FPDF_ERR_SECURITY: 60 jniThrowException(env, "java/lang/SecurityException", "unsupported security scheme"); 61 break; 62 case FPDF_ERR_PAGE: 63 jniThrowException(env, "java/io/IOException", "page not found or content error"); 64 break; 65#ifdef PDF_ENABLE_XFA 66 case FPDF_ERR_XFALOAD: 67 jniThrowException(env, "java/lang/Exception", "load XFA error"); 68 break; 69 case FPDF_ERR_XFALAYOUT: 70 jniThrowException(env, "java/lang/Exception", "layout XFA error"); 71 break; 72#endif // PDF_ENABLE_XFA 73 case FPDF_ERR_UNKNOWN: 74 default: 75 jniThrowExceptionFmt(env, "java/lang/Exception", "unknown error %d", error); 76 } 77 78 return true; 79} 80 81static bool initializeLibraryIfNeeded(JNIEnv* env) { 82 if (sUnmatchedPdfiumInitRequestCount == 0) { 83 FPDF_InitLibrary(); 84 85 HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false); 86 } 87 88 sUnmatchedPdfiumInitRequestCount++; 89 return true; 90} 91 92static void destroyLibraryIfNeeded(JNIEnv* env, bool handleError) { 93 if (sUnmatchedPdfiumInitRequestCount == 1) { 94 FPDF_DestroyLibrary(); 95 96 if (handleError) { 97 HANDLE_PDFIUM_ERROR_STATE(env); 98 } 99 } 100 101 sUnmatchedPdfiumInitRequestCount--; 102} 103 104jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) { 105 bool isInitialized = initializeLibraryIfNeeded(env); 106 if (!isInitialized) { 107 return -1; 108 } 109 110 FPDF_FILEACCESS loader; 111 loader.m_FileLen = size; 112 loader.m_Param = reinterpret_cast<void*>(intptr_t(fd)); 113 loader.m_GetBlock = &getBlock; 114 115 FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL); 116 if (!document) { 117 forwardPdfiumError(env); 118 destroyLibraryIfNeeded(env, false); 119 return -1; 120 } 121 122 return reinterpret_cast<jlong>(document); 123} 124 125void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) { 126 FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 127 FPDF_CloseDocument(document); 128 HANDLE_PDFIUM_ERROR_STATE(env) 129 130 destroyLibraryIfNeeded(env, true); 131} 132 133jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) { 134 FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 135 136 int pageCount = FPDF_GetPageCount(document); 137 HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1); 138 139 return pageCount; 140} 141 142jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) { 143 FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 144 145 FPDF_BOOL printScaling = FPDF_VIEWERREF_GetPrintScaling(document); 146 HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false); 147 148 return printScaling ? JNI_TRUE : JNI_FALSE; 149} 150 151}; 152