174c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes/* 274c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * Licensed to the Apache Software Foundation (ASF) under one or more 374c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * contributor license agreements. See the NOTICE file distributed with 474c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * this work for additional information regarding copyright ownership. 574c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * The ASF licenses this file to You under the Apache License, Version 2.0 674c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * (the "License"); you may not use this file except in compliance with 774c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * the License. You may obtain a copy of the License at 874c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * 974c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * http://www.apache.org/licenses/LICENSE-2.0 1074c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * 1174c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * Unless required by applicable law or agreed to in writing, software 1274c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS, 1374c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1474c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * See the License for the specific language governing permissions and 1574c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes * limitations under the License. 1674c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes */ 1774c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 18abf945fb9ce99d8c2769ac5b2691b2732fa59887Elliott Hughes#define LOG_TAG "Deflater" 19abf945fb9ce99d8c2769ac5b2691b2732fa59887Elliott Hughes 20a9f5c16a864ff63ba63f810410f8a27c086d5d52Elliott Hughes#include "JniConstants.h" 21011ed31c4d057d973931fa81a09d8c576a72d82aKenny Root#include "JniException.h" 2299c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes#include "ScopedPrimitiveArray.h" 233aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes#include "ZipUtilities.h" 24011ed31c4d057d973931fa81a09d8c576a72d82aKenny Root#include "zutil.h" // For DEF_WBITS and DEF_MEM_LEVEL. 2574c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 2674c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughesstatic void Deflater_setDictionaryImpl(JNIEnv* env, jobject, jbyteArray dict, int off, int len, jlong handle) { 2774c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes toNativeZipStream(handle)->setDictionary(env, dict, off, len, false); 2874c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 2974c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 3044e0e560c92338110953ce806df475fedcdf926eBrian Carlstromstatic jlong Deflater_getTotalInImpl(JNIEnv*, jobject, jlong handle) { 3174c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes return toNativeZipStream(handle)->stream.total_in; 3274c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 3374c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 3444e0e560c92338110953ce806df475fedcdf926eBrian Carlstromstatic jlong Deflater_getTotalOutImpl(JNIEnv*, jobject, jlong handle) { 3574c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes return toNativeZipStream(handle)->stream.total_out; 3674c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 3774c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 3844e0e560c92338110953ce806df475fedcdf926eBrian Carlstromstatic jint Deflater_getAdlerImpl(JNIEnv*, jobject, jlong handle) { 3974c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes return toNativeZipStream(handle)->stream.adler; 4074c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 4174c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 4274c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughesstatic jlong Deflater_createStream(JNIEnv * env, jobject, jint level, jint strategy, jboolean noHeader) { 4374c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes UniquePtr<NativeZipStream> jstream(new NativeZipStream); 4474c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes if (jstream.get() == NULL) { 4574c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes jniThrowOutOfMemoryError(env, NULL); 4674c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes return -1; 4774c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes } 4874c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 492d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes /* 502d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * See zlib.h for documentation of the deflateInit2 windowBits and memLevel parameters. 512d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * 522d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * zconf.h says the "requirements for deflate are (in bytes): 532d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * (1 << (windowBits+2)) + (1 << (memLevel+9)) 542d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) 552d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * plus a few kilobytes for small objects." 562d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes */ 57909a18fd6628cee6718865a7b7bf2534ea25f5ecElliott Hughes int windowBits = noHeader ? -DEF_WBITS : DEF_WBITS; 58909a18fd6628cee6718865a7b7bf2534ea25f5ecElliott Hughes int memLevel = DEF_MEM_LEVEL; 592d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes int err = deflateInit2(&jstream->stream, level, Z_DEFLATED, windowBits, memLevel, strategy); 6074c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes if (err != Z_OK) { 61011ed31c4d057d973931fa81a09d8c576a72d82aKenny Root throwExceptionForZlibError(env, "java/lang/IllegalArgumentException", err, jstream.get()); 6274c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes return -1; 6374c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes } 6474c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes return reinterpret_cast<uintptr_t>(jstream.release()); 6574c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 6674c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 6774c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughesstatic void Deflater_setInputImpl(JNIEnv* env, jobject, jbyteArray buf, jint off, jint len, jlong handle) { 6874c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes toNativeZipStream(handle)->setInput(env, buf, off, len); 6974c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 7074c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 712d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughesstatic jint Deflater_deflateImpl(JNIEnv* env, jobject recv, jbyteArray buf, int off, int len, jlong handle, int flushStyle) { 7274c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes NativeZipStream* stream = toNativeZipStream(handle); 730adb7b318dd5d67559d5b31b1ef3280dd72e1f5fElliott Hughes ScopedByteArrayRW out(env, buf); 7499c59bfa432e36933a7a5033fba8b89209f737bcElliott Hughes if (out.get() == NULL) { 7574c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes return -1; 7674c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes } 770adb7b318dd5d67559d5b31b1ef3280dd72e1f5fElliott Hughes stream->stream.next_out = reinterpret_cast<Bytef*>(out.get() + off); 782d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes stream->stream.avail_out = len; 792d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes 80fa5cdaa79ff491dd5c05d72baad27f931cf2d08eElliott Hughes Bytef* initialNextIn = stream->stream.next_in; 81fa5cdaa79ff491dd5c05d72baad27f931cf2d08eElliott Hughes Bytef* initialNextOut = stream->stream.next_out; 822d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes 832d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes int err = deflate(&stream->stream, flushStyle); 842d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes switch (err) { 852d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes case Z_OK: 862d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes break; 872d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes case Z_STREAM_END: 882d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes static jfieldID finished = env->GetFieldID(JniConstants::deflaterClass, "finished", "Z"); 892d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes env->SetBooleanField(recv, finished, JNI_TRUE); 902d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes break; 912d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes case Z_BUF_ERROR: 922d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes // zlib reports this "if no progress is possible (for example avail_in or avail_out was 932d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes // zero) ... Z_BUF_ERROR is not fatal, and deflate() can be called again with more 942d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes // input and more output space to continue compressing". 952d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes break; 962d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes default: 97011ed31c4d057d973931fa81a09d8c576a72d82aKenny Root throwExceptionForZlibError(env, "java/util/zip/DataFormatException", err, stream); 982d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes return -1; 9974c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes } 1002d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes 101fa5cdaa79ff491dd5c05d72baad27f931cf2d08eElliott Hughes jint bytesRead = stream->stream.next_in - initialNextIn; 102fa5cdaa79ff491dd5c05d72baad27f931cf2d08eElliott Hughes jint bytesWritten = stream->stream.next_out - initialNextOut; 103fa5cdaa79ff491dd5c05d72baad27f931cf2d08eElliott Hughes 104fa5cdaa79ff491dd5c05d72baad27f931cf2d08eElliott Hughes static jfieldID inReadField = env->GetFieldID(JniConstants::deflaterClass, "inRead", "I"); 105fa5cdaa79ff491dd5c05d72baad27f931cf2d08eElliott Hughes jint inReadValue = env->GetIntField(recv, inReadField); 106fa5cdaa79ff491dd5c05d72baad27f931cf2d08eElliott Hughes inReadValue += bytesRead; 107fa5cdaa79ff491dd5c05d72baad27f931cf2d08eElliott Hughes env->SetIntField(recv, inReadField, inReadValue); 108fa5cdaa79ff491dd5c05d72baad27f931cf2d08eElliott Hughes return bytesWritten; 10974c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 11074c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 11144e0e560c92338110953ce806df475fedcdf926eBrian Carlstromstatic void Deflater_endImpl(JNIEnv*, jobject, jlong handle) { 11274c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes NativeZipStream* stream = toNativeZipStream(handle); 11374c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes deflateEnd(&stream->stream); 11474c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes delete stream; 11574c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 11674c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 11774c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughesstatic void Deflater_resetImpl(JNIEnv* env, jobject, jlong handle) { 11874c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes NativeZipStream* stream = toNativeZipStream(handle); 11974c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes int err = deflateReset(&stream->stream); 12074c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes if (err != Z_OK) { 121011ed31c4d057d973931fa81a09d8c576a72d82aKenny Root throwExceptionForZlibError(env, "java/lang/IllegalArgumentException", err, stream); 12274c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes } 12374c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 12474c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 12574c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughesstatic void Deflater_setLevelsImpl(JNIEnv* env, jobject, int level, int strategy, jlong handle) { 12674c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes NativeZipStream* stream = toNativeZipStream(handle); 127b7f0ced490fa5c5ad389c58b8584def84391f591Elliott Hughes // The deflateParams documentation says that avail_out must never be 0 because it may be 128b7f0ced490fa5c5ad389c58b8584def84391f591Elliott Hughes // necessary to flush, but the Java API ensures that we only get here if there's nothing 129b7f0ced490fa5c5ad389c58b8584def84391f591Elliott Hughes // to flush. To be on the safe side, make sure that we're not pointing to a no longer valid 130b7f0ced490fa5c5ad389c58b8584def84391f591Elliott Hughes // buffer. 131b7f0ced490fa5c5ad389c58b8584def84391f591Elliott Hughes stream->stream.next_out = reinterpret_cast<Bytef*>(NULL); 132b7f0ced490fa5c5ad389c58b8584def84391f591Elliott Hughes stream->stream.avail_out = 0; 13374c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes int err = deflateParams(&stream->stream, level, strategy); 13474c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes if (err != Z_OK) { 135011ed31c4d057d973931fa81a09d8c576a72d82aKenny Root throwExceptionForZlibError(env, "java/lang/IllegalStateException", err, stream); 13674c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes } 13774c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 13874c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes 13974c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughesstatic JNINativeMethod gMethods[] = { 140e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(Deflater, createStream, "(IIZ)J"), 141e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(Deflater, deflateImpl, "([BIIJI)I"), 142e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(Deflater, endImpl, "(J)V"), 143e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(Deflater, getAdlerImpl, "(J)I"), 144e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(Deflater, getTotalInImpl, "(J)J"), 145e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(Deflater, getTotalOutImpl, "(J)J"), 146e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(Deflater, resetImpl, "(J)V"), 147e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(Deflater, setDictionaryImpl, "([BIIJ)V"), 148e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(Deflater, setInputImpl, "([BIIJ)V"), 149e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes NATIVE_METHOD(Deflater, setLevelsImpl, "(IIJ)V"), 15074c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes}; 1517cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughesvoid register_java_util_zip_Deflater(JNIEnv* env) { 1527cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughes jniRegisterNativeMethods(env, "java/util/zip/Deflater", gMethods, NELEM(gMethods)); 15374c05e2a892f236c8648af7f4cfb2bcb483f267bElliott Hughes} 154