PdfEditor.cpp revision ed6b9dff563c5e22f040ff37e12c0d771e0478ae
162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav/*
262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * Copyright (C) 2014 The Android Open Source Project
362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav *
462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * Licensed under the Apache License, Version 2.0 (the "License");
562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * you may not use this file except in compliance with the License.
662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * You may obtain a copy of the License at
762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav *
862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav *      http://www.apache.org/licenses/LICENSE-2.0
962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav *
1062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * Unless required by applicable law or agreed to in writing, software
1162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * distributed under the License is distributed on an "AS IS" BASIS,
1262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * See the License for the specific language governing permissions and
1462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * limitations under the License.
1562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav */
1662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
1762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include "jni.h"
1862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include "JNIHelp.h"
1962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include "fpdfview.h"
2062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include "fpdfedit.h"
2162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include "fpdfsave.h"
2262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
23ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include <core_jni_helpers.h>
2462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include <vector>
2562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include <utils/Log.h>
2662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include <unistd.h>
2762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include <sys/types.h>
2862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include <unistd.h>
2962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
3062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavnamespace android {
3162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
3262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic Mutex sLock;
3362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
3462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic int sUnmatchedInitRequestCount = 0;
3562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
3662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic void initializeLibraryIfNeeded() {
3762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    Mutex::Autolock _l(sLock);
3862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    if (sUnmatchedInitRequestCount == 0) {
3962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        FPDF_InitLibrary(NULL);
4062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
4162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    sUnmatchedInitRequestCount++;
4262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
4362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
4462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic void destroyLibraryIfNeeded() {
4562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    Mutex::Autolock _l(sLock);
4662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    sUnmatchedInitRequestCount--;
4762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    if (sUnmatchedInitRequestCount == 0) {
4862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav       FPDF_DestroyLibrary();
4962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
5062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
5162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
5262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
5362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        unsigned long size) {
5462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    const int fd = reinterpret_cast<intptr_t>(param);
5562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    const int readCount = pread(fd, outBuffer, size, position);
5662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    if (readCount < 0) {
5762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        ALOGE("Cannot read from file descriptor. Error:%d", errno);
5862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        return 0;
5962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
6062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    return 1;
6162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
6262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
6362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) {
6462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    initializeLibraryIfNeeded();
6562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
6662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDF_FILEACCESS loader;
6762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    loader.m_FileLen = size;
6862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
6962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    loader.m_GetBlock = &getBlock;
7062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
7162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
7262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
7362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    if (!document) {
7462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        const long error = FPDF_GetLastError();
7546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert        jniThrowExceptionFmt(env, "java/io/IOException",
7646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert                "cannot create document. Error: %ld", error);
7762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        destroyLibraryIfNeeded();
7862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        return -1;
7962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
8062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
8162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    return reinterpret_cast<jlong>(document);
8262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
8362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
8462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
8562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
8662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDF_CloseDocument(document);
8762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    destroyLibraryIfNeeded();
8862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
8962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
9062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
9162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
9262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    return FPDF_GetPageCount(document);
9362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
9462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
9562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic jint nativeRemovePage(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex) {
9662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
9762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDFPage_Delete(document, pageIndex);
9862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    return FPDF_GetPageCount(document);
9962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
10062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
10162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstruct PdfToFdWriter : FPDF_FILEWRITE {
10262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    int dstFd;
10362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav};
10462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
10562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic bool writeAllBytes(const int fd, const void* buffer, const size_t byteCount) {
10662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    char* writeBuffer = static_cast<char*>(const_cast<void*>(buffer));
10762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    size_t remainingBytes = byteCount;
10862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    while (remainingBytes > 0) {
10962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes);
11062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        if (writtenByteCount == -1) {
11162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            if (errno == EINTR) {
11262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav                continue;
11362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            }
11462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
11562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav                    "Error writing to buffer: %d", errno);
11662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            return false;
11762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        }
11862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        remainingBytes -= writtenByteCount;
11962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        writeBuffer += writtenByteCount;
12062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
12162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    return true;
12262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
12362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
12462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic int writeBlock(FPDF_FILEWRITE* owner, const void* buffer, unsigned long size) {
12562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    const PdfToFdWriter* writer = reinterpret_cast<PdfToFdWriter*>(owner);
12662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    const bool success = writeAllBytes(writer->dstFd, buffer, size);
12792ddfcfff5cec32456e2d1e0d96671f1eb0e2986Bernhard Rosenkränzer    if (!success) {
12862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        ALOGE("Cannot write to file descriptor. Error:%d", errno);
12962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        return 0;
13062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
13162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    return 1;
13262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
13362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
13462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) {
13562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
13662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    PdfToFdWriter writer;
13762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    writer.dstFd = fd;
13862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    writer.WriteBlock = &writeBlock;
13962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    const bool success = FPDF_SaveAsCopy(document, &writer, FPDF_NO_INCREMENTAL);
14062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    if (!success) {
14146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert        jniThrowExceptionFmt(env, "java/io/IOException",
14246d8444631b4b1253a76bfcc78a29d26014d022fDan Albert                "cannot write to fd. Error: %d", errno);
14362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        destroyLibraryIfNeeded();
14462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
14562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
14662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
14762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic JNINativeMethod gPdfEditor_Methods[] = {
14862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    {"nativeOpen", "(IJ)J", (void*) nativeOpen},
14962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    {"nativeClose", "(J)V", (void*) nativeClose},
15062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
15162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    {"nativeRemovePage", "(JI)I", (void*) nativeRemovePage},
15262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    {"nativeWrite", "(JI)V", (void*) nativeWrite}
15362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav};
15462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
15562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavint register_android_graphics_pdf_PdfEditor(JNIEnv* env) {
156ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    return android::RegisterMethodsOrDie(
15762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods,
15862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            NELEM(gPdfEditor_Methods));
15962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav};
16062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
16162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav};
162