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