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 #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 void initializeLibraryIfNeeded(JNIEnv* env) {
82 if (sUnmatchedPdfiumInitRequestCount == 0) {
83 FPDF_InitLibrary();
84 }
85
86 sUnmatchedPdfiumInitRequestCount++;
87 }
88
destroyLibraryIfNeeded(JNIEnv * env,bool handleError)89 static void destroyLibraryIfNeeded(JNIEnv* env, bool handleError) {
90 if (sUnmatchedPdfiumInitRequestCount == 1) {
91 FPDF_DestroyLibrary();
92 }
93
94 sUnmatchedPdfiumInitRequestCount--;
95 }
96
nativeOpen(JNIEnv * env,jclass thiz,jint fd,jlong size)97 jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) {
98 initializeLibraryIfNeeded(env);
99
100 FPDF_FILEACCESS loader;
101 loader.m_FileLen = size;
102 loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
103 loader.m_GetBlock = &getBlock;
104
105 FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
106 if (!document) {
107 forwardPdfiumError(env);
108 destroyLibraryIfNeeded(env, false);
109 return -1;
110 }
111
112 return reinterpret_cast<jlong>(document);
113 }
114
nativeClose(JNIEnv * env,jclass thiz,jlong documentPtr)115 void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
116 FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
117 FPDF_CloseDocument(document);
118
119 destroyLibraryIfNeeded(env, true);
120 }
121
nativeGetPageCount(JNIEnv * env,jclass thiz,jlong documentPtr)122 jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
123 FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
124
125 return FPDF_GetPageCount(document);
126 }
127
nativeScaleForPrinting(JNIEnv * env,jclass thiz,jlong documentPtr)128 jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
129 FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
130 FPDF_BOOL printScaling = FPDF_VIEWERREF_GetPrintScaling(document);
131
132 return printScaling ? JNI_TRUE : JNI_FALSE;
133 }
134
135 };
136