• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 namespace android {
28 
29 static int sUnmatchedPdfiumInitRequestCount = 0;
30 
getBlock(void * param,unsigned long position,unsigned char * outBuffer,unsigned long size)31 int 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.
forwardPdfiumError(JNIEnv * env)44 bool 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 
initializeLibraryIfNeeded(JNIEnv * env)81 static 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 
destroyLibraryIfNeeded(JNIEnv * env,bool handleError)92 static 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 
nativeOpen(JNIEnv * env,jclass thiz,jint fd,jlong size)104 jlong 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 
nativeClose(JNIEnv * env,jclass thiz,jlong documentPtr)125 void 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 
nativeGetPageCount(JNIEnv * env,jclass thiz,jlong documentPtr)133 jint 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 
nativeScaleForPrinting(JNIEnv * env,jclass thiz,jlong documentPtr)142 jboolean 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