| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 <config.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <dlfcn.h> |
| |
| #include "org_apache_hadoop_io_compress_bzip2.h" |
| #include "org_apache_hadoop_io_compress_bzip2_Bzip2Compressor.h" |
| |
| static jfieldID Bzip2Compressor_stream; |
| static jfieldID Bzip2Compressor_uncompressedDirectBuf; |
| static jfieldID Bzip2Compressor_uncompressedDirectBufOff; |
| static jfieldID Bzip2Compressor_uncompressedDirectBufLen; |
| static jfieldID Bzip2Compressor_compressedDirectBuf; |
| static jfieldID Bzip2Compressor_directBufferSize; |
| static jfieldID Bzip2Compressor_finish; |
| static jfieldID Bzip2Compressor_finished; |
| |
| static int (*dlsym_BZ2_bzCompressInit)(bz_stream*, int, int, int); |
| static int (*dlsym_BZ2_bzCompress)(bz_stream*, int); |
| static int (*dlsym_BZ2_bzCompressEnd)(bz_stream*); |
| |
| JNIEXPORT void JNICALL |
| Java_org_apache_hadoop_io_compress_bzip2_Bzip2Compressor_initIDs( |
| JNIEnv *env, jclass class, jstring libname) |
| { |
| const char *bzlib_name = NULL; |
| const char *java_lib_name = (*env)->GetStringUTFChars(env, libname, NULL); |
| if (java_lib_name == NULL) { |
| // Java code will get OutOfMemoryException thrown by GetStringUTFChars |
| goto cleanup; |
| } |
| |
| if (strcmp(java_lib_name, "system-native") == 0) { |
| bzlib_name = HADOOP_BZIP2_LIBRARY; |
| } else { |
| bzlib_name = java_lib_name; |
| } |
| |
| // Load the native library. |
| void *libbz2 = dlopen(bzlib_name, RTLD_LAZY | RTLD_GLOBAL); |
| if (!libbz2) { |
| THROW(env, "java/lang/UnsatisfiedLinkError", |
| "Cannot load bzip2 native library"); |
| goto cleanup; |
| } |
| |
| // Locate the requisite symbols from libbz2.so. |
| dlerror(); // Clear any existing error. |
| LOAD_DYNAMIC_SYMBOL(dlsym_BZ2_bzCompressInit, env, libbz2, |
| "BZ2_bzCompressInit"); |
| LOAD_DYNAMIC_SYMBOL(dlsym_BZ2_bzCompress, env, libbz2, |
| "BZ2_bzCompress"); |
| LOAD_DYNAMIC_SYMBOL(dlsym_BZ2_bzCompressEnd, env, libbz2, |
| "BZ2_bzCompressEnd"); |
| |
| // Initialize the requisite fieldIds. |
| Bzip2Compressor_stream = (*env)->GetFieldID(env, class, "stream", "J"); |
| Bzip2Compressor_finish = (*env)->GetFieldID(env, class, "finish", "Z"); |
| Bzip2Compressor_finished = (*env)->GetFieldID(env, class, "finished", "Z"); |
| Bzip2Compressor_uncompressedDirectBuf = (*env)->GetFieldID(env, class, |
| "uncompressedDirectBuf", |
| "Ljava/nio/Buffer;"); |
| Bzip2Compressor_uncompressedDirectBufOff = (*env)->GetFieldID(env, class, |
| "uncompressedDirectBufOff", |
| "I"); |
| Bzip2Compressor_uncompressedDirectBufLen = (*env)->GetFieldID(env, class, |
| "uncompressedDirectBufLen", |
| "I"); |
| Bzip2Compressor_compressedDirectBuf = (*env)->GetFieldID(env, class, |
| "compressedDirectBuf", |
| "Ljava/nio/Buffer;"); |
| Bzip2Compressor_directBufferSize = (*env)->GetFieldID(env, class, |
| "directBufferSize", "I"); |
| cleanup: |
| if(java_lib_name != NULL) { |
| (*env)->ReleaseStringUTFChars(env,libname,java_lib_name); |
| java_lib_name = NULL; |
| } |
| } |
| |
| JNIEXPORT jlong JNICALL |
| Java_org_apache_hadoop_io_compress_bzip2_Bzip2Compressor_init( |
| JNIEnv *env, jclass class, jint blockSize, jint workFactor) |
| { |
| // Create a bz_stream. |
| bz_stream *stream = malloc(sizeof(bz_stream)); |
| if (!stream) { |
| THROW(env, "java/lang/OutOfMemoryError", NULL); |
| return (jlong)0; |
| } |
| memset((void*)stream, 0, sizeof(bz_stream)); |
| |
| // Initialize stream. |
| int rv = (*dlsym_BZ2_bzCompressInit)(stream, blockSize, 0, workFactor); |
| if (rv != BZ_OK) { |
| // Contingency - Report error by throwing appropriate exceptions. |
| free(stream); |
| stream = NULL; |
| |
| switch (rv) { |
| case BZ_MEM_ERROR: |
| { |
| THROW(env, "java/lang/OutOfMemoryError", NULL); |
| } |
| break; |
| case BZ_PARAM_ERROR: |
| { |
| THROW(env, |
| "java/lang/IllegalArgumentException", |
| NULL); |
| } |
| break; |
| default: |
| { |
| THROW(env, "java/lang/InternalError", NULL); |
| } |
| break; |
| } |
| } |
| |
| return JLONG(stream); |
| } |
| |
| JNIEXPORT jint JNICALL |
| Java_org_apache_hadoop_io_compress_bzip2_Bzip2Compressor_deflateBytesDirect( |
| JNIEnv *env, jobject this) |
| { |
| // Get members of Bzip2Compressor. |
| bz_stream *stream = BZSTREAM((*env)->GetLongField(env, this, |
| Bzip2Compressor_stream)); |
| if (!stream) { |
| THROW(env, "java/lang/NullPointerException", NULL); |
| return (jint)0; |
| } |
| |
| jobject uncompressed_direct_buf = (*env)->GetObjectField(env, this, |
| Bzip2Compressor_uncompressedDirectBuf); |
| jint uncompressed_direct_buf_off = (*env)->GetIntField(env, this, |
| Bzip2Compressor_uncompressedDirectBufOff); |
| jint uncompressed_direct_buf_len = (*env)->GetIntField(env, this, |
| Bzip2Compressor_uncompressedDirectBufLen); |
| |
| jobject compressed_direct_buf = (*env)->GetObjectField(env, this, |
| Bzip2Compressor_compressedDirectBuf); |
| jint compressed_direct_buf_len = (*env)->GetIntField(env, this, |
| Bzip2Compressor_directBufferSize); |
| |
| jboolean finish = (*env)->GetBooleanField(env, this, |
| Bzip2Compressor_finish); |
| |
| // Get the input and output direct buffers. |
| char* uncompressed_bytes = (*env)->GetDirectBufferAddress(env, |
| uncompressed_direct_buf); |
| char* compressed_bytes = (*env)->GetDirectBufferAddress(env, |
| compressed_direct_buf); |
| |
| if (!uncompressed_bytes || !compressed_bytes) { |
| return (jint)0; |
| } |
| |
| // Re-calibrate the bz_stream. |
| stream->next_in = uncompressed_bytes + uncompressed_direct_buf_off; |
| stream->avail_in = uncompressed_direct_buf_len; |
| stream->next_out = compressed_bytes; |
| stream->avail_out = compressed_direct_buf_len; |
| |
| // Compress. |
| int rv = dlsym_BZ2_bzCompress(stream, finish ? BZ_FINISH : BZ_RUN); |
| |
| jint no_compressed_bytes = 0; |
| switch (rv) { |
| // Contingency? - Report error by throwing appropriate exceptions. |
| case BZ_STREAM_END: |
| { |
| (*env)->SetBooleanField(env, this, |
| Bzip2Compressor_finished, |
| JNI_TRUE); |
| } // cascade |
| case BZ_RUN_OK: |
| case BZ_FINISH_OK: |
| { |
| uncompressed_direct_buf_off += |
| uncompressed_direct_buf_len - stream->avail_in; |
| (*env)->SetIntField(env, this, |
| Bzip2Compressor_uncompressedDirectBufOff, |
| uncompressed_direct_buf_off); |
| (*env)->SetIntField(env, this, |
| Bzip2Compressor_uncompressedDirectBufLen, |
| stream->avail_in); |
| no_compressed_bytes = |
| compressed_direct_buf_len - stream->avail_out; |
| } |
| break; |
| default: |
| { |
| THROW(env, "java/lang/InternalError", NULL); |
| } |
| break; |
| } |
| |
| return no_compressed_bytes; |
| } |
| |
| JNIEXPORT jlong JNICALL |
| Java_org_apache_hadoop_io_compress_bzip2_Bzip2Compressor_getBytesRead( |
| JNIEnv *env, jclass class, jlong stream) |
| { |
| const bz_stream* strm = BZSTREAM(stream); |
| return ((jlong)strm->total_in_hi32 << 32) | strm->total_in_lo32; |
| } |
| |
| JNIEXPORT jlong JNICALL |
| Java_org_apache_hadoop_io_compress_bzip2_Bzip2Compressor_getBytesWritten( |
| JNIEnv *env, jclass class, jlong stream) |
| { |
| const bz_stream* strm = BZSTREAM(stream); |
| return ((jlong)strm->total_out_hi32 << 32) | strm->total_out_lo32; |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_org_apache_hadoop_io_compress_bzip2_Bzip2Compressor_end( |
| JNIEnv *env, jclass class, jlong stream) |
| { |
| if (dlsym_BZ2_bzCompressEnd(BZSTREAM(stream)) != BZ_OK) { |
| THROW(env, "java/lang/InternalError", NULL); |
| } |
| |
| free(BZSTREAM(stream)); |
| |
| } |
| |
| JNIEXPORT jstring JNICALL |
| Java_org_apache_hadoop_io_compress_bzip2_Bzip2Compressor_getLibraryName(JNIEnv *env, jclass class) { |
| #ifdef UNIX |
| if (dlsym_BZ2_bzCompress) { |
| Dl_info dl_info; |
| if(dladdr( |
| dlsym_BZ2_bzCompress, |
| &dl_info)) { |
| return (*env)->NewStringUTF(env, dl_info.dli_fname); |
| } |
| } |
| #endif |
| return (*env)->NewStringUTF(env, HADOOP_BZIP2_LIBRARY); |
| } |
| |
| /** |
| * vim: sw=2: ts=2: et: |
| */ |
| |