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 <nativehelper/JNIHelp.h>
21
22 #include "fpdfview.h"
23
24 #undef LOG_TAG
25 #define LOG_TAG "PdfUtils"
26 #include <utils/Log.h>
27
28 namespace android {
29
30 static int sUnmatchedPdfiumInitRequestCount = 0;
31
getBlock(void * param,unsigned long position,unsigned char * outBuffer,unsigned long size)32 int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
33 unsigned long size) {
34 const int fd = reinterpret_cast<intptr_t>(param);
35 const int readCount = pread(fd, outBuffer, size, position);
36 if (readCount < 0) {
37 ALOGE("Cannot read from file descriptor. Error:%d", errno);
38 return 0;
39 }
40 return 1;
41 }
42
43 // Check if the last pdfium command failed and if so, forward the error to java via an exception. If
44 // this function returns true an exception is pending.
forwardPdfiumError(JNIEnv * env)45 bool forwardPdfiumError(JNIEnv* env) {
46 long error = FPDF_GetLastError();
47 switch (error) {
48 case FPDF_ERR_SUCCESS:
49 return false;
50 case FPDF_ERR_FILE:
51 jniThrowException(env, "java/io/IOException", "file not found or cannot be opened");
52 break;
53 case FPDF_ERR_FORMAT:
54 jniThrowException(env, "java/io/IOException", "file not in PDF format or corrupted");
55 break;
56 case FPDF_ERR_PASSWORD:
57 jniThrowException(env, "java/lang/SecurityException",
58 "password required or incorrect password");
59 break;
60 case FPDF_ERR_SECURITY:
61 jniThrowException(env, "java/lang/SecurityException", "unsupported security scheme");
62 break;
63 case FPDF_ERR_PAGE:
64 jniThrowException(env, "java/io/IOException", "page not found or content error");
65 break;
66 #ifdef PDF_ENABLE_XFA
67 case FPDF_ERR_XFALOAD:
68 jniThrowException(env, "java/lang/Exception", "load XFA error");
69 break;
70 case FPDF_ERR_XFALAYOUT:
71 jniThrowException(env, "java/lang/Exception", "layout XFA error");
72 break;
73 #endif // PDF_ENABLE_XFA
74 case FPDF_ERR_UNKNOWN:
75 default:
76 jniThrowExceptionFmt(env, "java/lang/Exception", "unknown error %d", error);
77 }
78
79 return true;
80 }
81
initializeLibraryIfNeeded(JNIEnv * env)82 static void initializeLibraryIfNeeded(JNIEnv* env) {
83 if (sUnmatchedPdfiumInitRequestCount == 0) {
84 FPDF_InitLibrary();
85 }
86
87 sUnmatchedPdfiumInitRequestCount++;
88 }
89
destroyLibraryIfNeeded(JNIEnv * env,bool handleError)90 static void destroyLibraryIfNeeded(JNIEnv* env, bool handleError) {
91 if (sUnmatchedPdfiumInitRequestCount == 1) {
92 FPDF_DestroyLibrary();
93 }
94
95 sUnmatchedPdfiumInitRequestCount--;
96 }
97
nativeOpen(JNIEnv * env,jclass thiz,jint fd,jlong size)98 jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) {
99 initializeLibraryIfNeeded(env);
100
101 FPDF_FILEACCESS loader;
102 loader.m_FileLen = size;
103 loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
104 loader.m_GetBlock = &getBlock;
105
106 FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
107 if (!document) {
108 forwardPdfiumError(env);
109 destroyLibraryIfNeeded(env, false);
110 return -1;
111 }
112
113 return reinterpret_cast<jlong>(document);
114 }
115
nativeClose(JNIEnv * env,jclass thiz,jlong documentPtr)116 void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
117 FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
118 FPDF_CloseDocument(document);
119
120 destroyLibraryIfNeeded(env, true);
121 }
122
nativeGetPageCount(JNIEnv * env,jclass thiz,jlong documentPtr)123 jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
124 FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
125
126 return FPDF_GetPageCount(document);
127 }
128
nativeScaleForPrinting(JNIEnv * env,jclass thiz,jlong documentPtr)129 jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
130 FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
131 FPDF_BOOL printScaling = FPDF_VIEWERREF_GetPrintScaling(document);
132
133 return printScaling ? JNI_TRUE : JNI_FALSE;
134 }
135
136 };
137