Loading core/jni/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -129,6 +129,7 @@ LOCAL_SRC_FILES:= \ android/graphics/Xfermode.cpp \ android/graphics/YuvToJpegEncoder.cpp \ android/graphics/pdf/PdfDocument.cpp \ android/graphics/pdf/PdfEditor.cpp \ android/graphics/pdf/PdfRenderer.cpp \ android_media_AudioRecord.cpp \ android_media_AudioSystem.cpp \ Loading core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,7 @@ extern int register_android_graphics_Region(JNIEnv* env); extern int register_android_graphics_SurfaceTexture(JNIEnv* env); extern int register_android_graphics_Xfermode(JNIEnv* env); extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env); extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env); extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env); extern int register_android_view_DisplayEventReceiver(JNIEnv* env); extern int register_android_view_RenderNode(JNIEnv* env); Loading Loading @@ -1305,6 +1306,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_Xfermode), REG_JNI(register_android_graphics_YuvImage), REG_JNI(register_android_graphics_pdf_PdfDocument), REG_JNI(register_android_graphics_pdf_PdfEditor), REG_JNI(register_android_graphics_pdf_PdfRenderer), REG_JNI(register_android_database_CursorWindow), Loading core/jni/android/graphics/pdf/PdfEditor.cpp 0 → 100644 +161 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "jni.h" #include "JNIHelp.h" #include "fpdfview.h" #include "fpdfedit.h" #include "fpdfsave.h" #include <android_runtime/AndroidRuntime.h> #include <vector> #include <utils/Log.h> #include <unistd.h> #include <sys/types.h> #include <unistd.h> namespace android { static Mutex sLock; static int sUnmatchedInitRequestCount = 0; static void initializeLibraryIfNeeded() { Mutex::Autolock _l(sLock); if (sUnmatchedInitRequestCount == 0) { FPDF_InitLibrary(NULL); } sUnmatchedInitRequestCount++; } static void destroyLibraryIfNeeded() { Mutex::Autolock _l(sLock); sUnmatchedInitRequestCount--; if (sUnmatchedInitRequestCount == 0) { FPDF_DestroyLibrary(); } } static int getBlock(void* param, unsigned long position, unsigned char* outBuffer, unsigned long size) { const int fd = reinterpret_cast<intptr_t>(param); const int readCount = pread(fd, outBuffer, size, position); if (readCount < 0) { ALOGE("Cannot read from file descriptor. Error:%d", errno); return 0; } return 1; } static jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) { initializeLibraryIfNeeded(); FPDF_FILEACCESS loader; loader.m_FileLen = size; loader.m_Param = reinterpret_cast<void*>(intptr_t(fd)); loader.m_GetBlock = &getBlock; FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL); if (!document) { const long error = FPDF_GetLastError(); jniThrowException(env, "java/io/IOException", "cannot create document. Error:" + error); destroyLibraryIfNeeded(); return -1; } return reinterpret_cast<jlong>(document); } static void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) { FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); FPDF_CloseDocument(document); destroyLibraryIfNeeded(); } static jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) { FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); return FPDF_GetPageCount(document); } static jint nativeRemovePage(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex) { FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); FPDFPage_Delete(document, pageIndex); return FPDF_GetPageCount(document); } struct PdfToFdWriter : FPDF_FILEWRITE { int dstFd; }; static bool writeAllBytes(const int fd, const void* buffer, const size_t byteCount) { char* writeBuffer = static_cast<char*>(const_cast<void*>(buffer)); size_t remainingBytes = byteCount; while (remainingBytes > 0) { ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes); if (writtenByteCount == -1) { if (errno == EINTR) { continue; } __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Error writing to buffer: %d", errno); return false; } remainingBytes -= writtenByteCount; writeBuffer += writtenByteCount; } return true; } static int writeBlock(FPDF_FILEWRITE* owner, const void* buffer, unsigned long size) { const PdfToFdWriter* writer = reinterpret_cast<PdfToFdWriter*>(owner); const bool success = writeAllBytes(writer->dstFd, buffer, size); if (success < 0) { ALOGE("Cannot write to file descriptor. Error:%d", errno); return 0; } return 1; } static void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) { FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); PdfToFdWriter writer; writer.dstFd = fd; writer.WriteBlock = &writeBlock; const bool success = FPDF_SaveAsCopy(document, &writer, FPDF_NO_INCREMENTAL); if (!success) { jniThrowException(env, "java/io/IOException", "cannot write to fd. Error:" + errno); destroyLibraryIfNeeded(); } } static JNINativeMethod gPdfEditor_Methods[] = { {"nativeOpen", "(IJ)J", (void*) nativeOpen}, {"nativeClose", "(J)V", (void*) nativeClose}, {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount}, {"nativeRemovePage", "(JI)I", (void*) nativeRemovePage}, {"nativeWrite", "(JI)V", (void*) nativeWrite} }; int register_android_graphics_pdf_PdfEditor(JNIEnv* env) { return android::AndroidRuntime::registerNativeMethods( env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods, NELEM(gPdfEditor_Methods)); }; }; graphics/java/android/graphics/pdf/PdfEditor.java 0 → 100644 +162 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.graphics.pdf; import android.annotation.NonNull; import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import android.system.OsConstants; import dalvik.system.CloseGuard; import libcore.io.IoUtils; import libcore.io.Libcore; import java.io.IOException; /** * Class for editing PDF files. * * @hide */ public final class PdfEditor { private final CloseGuard mCloseGuard = CloseGuard.get(); private final long mNativeDocument; private int mPageCount; private ParcelFileDescriptor mInput; /** * Creates a new instance. * <p> * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>, * i.e. its data being randomly accessed, e.g. pointing to a file. After finishing * with this class you must call {@link #close()}. * </p> * <p> * <strong>Note:</strong> This class takes ownership of the passed in file descriptor * and is responsible for closing it when the editor is closed. * </p> * * @param input Seekable file descriptor to read from. * * @see #close() */ public PdfEditor(@NonNull ParcelFileDescriptor input) throws IOException { if (input == null) { throw new NullPointerException("input cannot be null"); } final long size; try { Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET); size = Libcore.os.fstat(input.getFileDescriptor()).st_size; } catch (ErrnoException ee) { throw new IllegalArgumentException("file descriptor not seekable"); } mInput = input; mNativeDocument = nativeOpen(mInput.getFd(), size); mPageCount = nativeGetPageCount(mNativeDocument); mCloseGuard.open("close"); } /** * Gets the number of pages in the document. * * @return The page count. */ public int getPageCount() { throwIfClosed(); return mPageCount; } /** * Removes the page with a given index. * * @param pageIndex The page to remove. */ public void removePage(int pageIndex) { throwIfClosed(); throwIfPageNotInDocument(pageIndex); mPageCount = nativeRemovePage(mNativeDocument, pageIndex); } /** * Writes the PDF file to the provided destination. * <p> * <strong>Note:</strong> This method takes ownership of the passed in file * descriptor and is responsible for closing it when writing completes. * </p> * @param output The destination. */ public void write(ParcelFileDescriptor output) throws IOException { try { throwIfClosed(); nativeWrite(mNativeDocument, output.getFd()); } finally { IoUtils.closeQuietly(output); } } /** * Closes this editor. You should not use this instance * after this method is called. */ public void close() { throwIfClosed(); doClose(); } @Override protected void finalize() throws Throwable { try { mCloseGuard.warnIfOpen(); if (mInput != null) { doClose(); } } finally { super.finalize(); } } private void doClose() { nativeClose(mNativeDocument); IoUtils.closeQuietly(mInput); mInput = null; mCloseGuard.close(); } private void throwIfClosed() { if (mInput == null) { throw new IllegalStateException("Already closed"); } } private void throwIfPageNotInDocument(int pageIndex) { if (pageIndex < 0 || pageIndex >= mPageCount) { throw new IllegalArgumentException("Invalid page index"); } } private static native long nativeOpen(int fd, long size); private static native void nativeClose(long documentPtr); private static native int nativeGetPageCount(long documentPtr); private static native int nativeRemovePage(long documentPtr, int pageIndex); private static native void nativeWrite(long documentPtr, int fd); } graphics/java/android/graphics/pdf/PdfRenderer.java +1 −1 Original line number Diff line number Diff line Loading @@ -239,7 +239,7 @@ public final class PdfRenderer implements AutoCloseable { } private void throwIfPageNotInDocument(int pageIndex) { if (pageIndex >= mPageCount) { if (pageIndex < 0 || pageIndex >= mPageCount) { throw new IllegalArgumentException("Invalid page index"); } } Loading Loading
core/jni/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -129,6 +129,7 @@ LOCAL_SRC_FILES:= \ android/graphics/Xfermode.cpp \ android/graphics/YuvToJpegEncoder.cpp \ android/graphics/pdf/PdfDocument.cpp \ android/graphics/pdf/PdfEditor.cpp \ android/graphics/pdf/PdfRenderer.cpp \ android_media_AudioRecord.cpp \ android_media_AudioSystem.cpp \ Loading
core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,7 @@ extern int register_android_graphics_Region(JNIEnv* env); extern int register_android_graphics_SurfaceTexture(JNIEnv* env); extern int register_android_graphics_Xfermode(JNIEnv* env); extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env); extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env); extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env); extern int register_android_view_DisplayEventReceiver(JNIEnv* env); extern int register_android_view_RenderNode(JNIEnv* env); Loading Loading @@ -1305,6 +1306,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_Xfermode), REG_JNI(register_android_graphics_YuvImage), REG_JNI(register_android_graphics_pdf_PdfDocument), REG_JNI(register_android_graphics_pdf_PdfEditor), REG_JNI(register_android_graphics_pdf_PdfRenderer), REG_JNI(register_android_database_CursorWindow), Loading
core/jni/android/graphics/pdf/PdfEditor.cpp 0 → 100644 +161 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "jni.h" #include "JNIHelp.h" #include "fpdfview.h" #include "fpdfedit.h" #include "fpdfsave.h" #include <android_runtime/AndroidRuntime.h> #include <vector> #include <utils/Log.h> #include <unistd.h> #include <sys/types.h> #include <unistd.h> namespace android { static Mutex sLock; static int sUnmatchedInitRequestCount = 0; static void initializeLibraryIfNeeded() { Mutex::Autolock _l(sLock); if (sUnmatchedInitRequestCount == 0) { FPDF_InitLibrary(NULL); } sUnmatchedInitRequestCount++; } static void destroyLibraryIfNeeded() { Mutex::Autolock _l(sLock); sUnmatchedInitRequestCount--; if (sUnmatchedInitRequestCount == 0) { FPDF_DestroyLibrary(); } } static int getBlock(void* param, unsigned long position, unsigned char* outBuffer, unsigned long size) { const int fd = reinterpret_cast<intptr_t>(param); const int readCount = pread(fd, outBuffer, size, position); if (readCount < 0) { ALOGE("Cannot read from file descriptor. Error:%d", errno); return 0; } return 1; } static jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) { initializeLibraryIfNeeded(); FPDF_FILEACCESS loader; loader.m_FileLen = size; loader.m_Param = reinterpret_cast<void*>(intptr_t(fd)); loader.m_GetBlock = &getBlock; FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL); if (!document) { const long error = FPDF_GetLastError(); jniThrowException(env, "java/io/IOException", "cannot create document. Error:" + error); destroyLibraryIfNeeded(); return -1; } return reinterpret_cast<jlong>(document); } static void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) { FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); FPDF_CloseDocument(document); destroyLibraryIfNeeded(); } static jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) { FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); return FPDF_GetPageCount(document); } static jint nativeRemovePage(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex) { FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); FPDFPage_Delete(document, pageIndex); return FPDF_GetPageCount(document); } struct PdfToFdWriter : FPDF_FILEWRITE { int dstFd; }; static bool writeAllBytes(const int fd, const void* buffer, const size_t byteCount) { char* writeBuffer = static_cast<char*>(const_cast<void*>(buffer)); size_t remainingBytes = byteCount; while (remainingBytes > 0) { ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes); if (writtenByteCount == -1) { if (errno == EINTR) { continue; } __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Error writing to buffer: %d", errno); return false; } remainingBytes -= writtenByteCount; writeBuffer += writtenByteCount; } return true; } static int writeBlock(FPDF_FILEWRITE* owner, const void* buffer, unsigned long size) { const PdfToFdWriter* writer = reinterpret_cast<PdfToFdWriter*>(owner); const bool success = writeAllBytes(writer->dstFd, buffer, size); if (success < 0) { ALOGE("Cannot write to file descriptor. Error:%d", errno); return 0; } return 1; } static void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) { FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); PdfToFdWriter writer; writer.dstFd = fd; writer.WriteBlock = &writeBlock; const bool success = FPDF_SaveAsCopy(document, &writer, FPDF_NO_INCREMENTAL); if (!success) { jniThrowException(env, "java/io/IOException", "cannot write to fd. Error:" + errno); destroyLibraryIfNeeded(); } } static JNINativeMethod gPdfEditor_Methods[] = { {"nativeOpen", "(IJ)J", (void*) nativeOpen}, {"nativeClose", "(J)V", (void*) nativeClose}, {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount}, {"nativeRemovePage", "(JI)I", (void*) nativeRemovePage}, {"nativeWrite", "(JI)V", (void*) nativeWrite} }; int register_android_graphics_pdf_PdfEditor(JNIEnv* env) { return android::AndroidRuntime::registerNativeMethods( env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods, NELEM(gPdfEditor_Methods)); }; };
graphics/java/android/graphics/pdf/PdfEditor.java 0 → 100644 +162 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.graphics.pdf; import android.annotation.NonNull; import android.os.ParcelFileDescriptor; import android.system.ErrnoException; import android.system.OsConstants; import dalvik.system.CloseGuard; import libcore.io.IoUtils; import libcore.io.Libcore; import java.io.IOException; /** * Class for editing PDF files. * * @hide */ public final class PdfEditor { private final CloseGuard mCloseGuard = CloseGuard.get(); private final long mNativeDocument; private int mPageCount; private ParcelFileDescriptor mInput; /** * Creates a new instance. * <p> * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>, * i.e. its data being randomly accessed, e.g. pointing to a file. After finishing * with this class you must call {@link #close()}. * </p> * <p> * <strong>Note:</strong> This class takes ownership of the passed in file descriptor * and is responsible for closing it when the editor is closed. * </p> * * @param input Seekable file descriptor to read from. * * @see #close() */ public PdfEditor(@NonNull ParcelFileDescriptor input) throws IOException { if (input == null) { throw new NullPointerException("input cannot be null"); } final long size; try { Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET); size = Libcore.os.fstat(input.getFileDescriptor()).st_size; } catch (ErrnoException ee) { throw new IllegalArgumentException("file descriptor not seekable"); } mInput = input; mNativeDocument = nativeOpen(mInput.getFd(), size); mPageCount = nativeGetPageCount(mNativeDocument); mCloseGuard.open("close"); } /** * Gets the number of pages in the document. * * @return The page count. */ public int getPageCount() { throwIfClosed(); return mPageCount; } /** * Removes the page with a given index. * * @param pageIndex The page to remove. */ public void removePage(int pageIndex) { throwIfClosed(); throwIfPageNotInDocument(pageIndex); mPageCount = nativeRemovePage(mNativeDocument, pageIndex); } /** * Writes the PDF file to the provided destination. * <p> * <strong>Note:</strong> This method takes ownership of the passed in file * descriptor and is responsible for closing it when writing completes. * </p> * @param output The destination. */ public void write(ParcelFileDescriptor output) throws IOException { try { throwIfClosed(); nativeWrite(mNativeDocument, output.getFd()); } finally { IoUtils.closeQuietly(output); } } /** * Closes this editor. You should not use this instance * after this method is called. */ public void close() { throwIfClosed(); doClose(); } @Override protected void finalize() throws Throwable { try { mCloseGuard.warnIfOpen(); if (mInput != null) { doClose(); } } finally { super.finalize(); } } private void doClose() { nativeClose(mNativeDocument); IoUtils.closeQuietly(mInput); mInput = null; mCloseGuard.close(); } private void throwIfClosed() { if (mInput == null) { throw new IllegalStateException("Already closed"); } } private void throwIfPageNotInDocument(int pageIndex) { if (pageIndex < 0 || pageIndex >= mPageCount) { throw new IllegalArgumentException("Invalid page index"); } } private static native long nativeOpen(int fd, long size); private static native void nativeClose(long documentPtr); private static native int nativeGetPageCount(long documentPtr); private static native int nativeRemovePage(long documentPtr, int pageIndex); private static native void nativeWrite(long documentPtr, int fd); }
graphics/java/android/graphics/pdf/PdfRenderer.java +1 −1 Original line number Diff line number Diff line Loading @@ -239,7 +239,7 @@ public final class PdfRenderer implements AutoCloseable { } private void throwIfPageNotInDocument(int pageIndex) { if (pageIndex >= mPageCount) { if (pageIndex < 0 || pageIndex >= mPageCount) { throw new IllegalArgumentException("Invalid page index"); } } Loading