1 /* 2 * Copyright (C) 2013 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 "error_codes.h" 18 #include "jni_defines.h" 19 #include "jpeg_hook.h" 20 21 #include <stddef.h> 22 #include <string.h> 23 24 void Mgr_init_destination_fcn(j_compress_ptr cinfo) { 25 DestManager *dst = reinterpret_cast<DestManager*>(cinfo->dest); 26 dst->mgr.next_output_byte = reinterpret_cast<JOCTET*>(dst->outStream->getBufferPtr()); 27 dst->mgr.free_in_buffer = dst->outStream->getBufferSize(); 28 } 29 30 boolean Mgr_empty_output_buffer_fcn(j_compress_ptr cinfo) { 31 DestManager *dst = reinterpret_cast<DestManager*>(cinfo->dest); 32 int32_t len = dst->outStream->getBufferSize(); 33 if (dst->outStream->write(len, 0) != J_SUCCESS) { 34 ERREXIT(cinfo, JERR_FILE_WRITE); 35 } 36 dst->mgr.next_output_byte = reinterpret_cast<JOCTET*>(dst->outStream->getBufferPtr()); 37 dst->mgr.free_in_buffer = len; 38 return TRUE; 39 } 40 41 void Mgr_term_destination_fcn(j_compress_ptr cinfo) { 42 DestManager *dst = reinterpret_cast<DestManager*>(cinfo->dest); 43 int32_t remaining = dst->outStream->getBufferSize() - dst->mgr.free_in_buffer; 44 if (dst->outStream->write(remaining, 0) != J_SUCCESS) { 45 ERREXIT(cinfo, JERR_FILE_WRITE); 46 } 47 } 48 49 int32_t MakeDst(j_compress_ptr cinfo, JNIEnv *env, jobject outStream) { 50 if (cinfo->dest != NULL) { 51 LOGE("DestManager already exists, cannot allocate!"); 52 return J_ERROR_FATAL; 53 } else { 54 size_t size = sizeof(DestManager); 55 cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small) 56 ((j_common_ptr) cinfo, JPOOL_PERMANENT, size); 57 if (cinfo->dest == NULL) { 58 LOGE("Could not allocate memory for DestManager."); 59 return J_ERROR_FATAL; 60 } 61 memset(cinfo->dest, '0', size); 62 } 63 DestManager *d = reinterpret_cast<DestManager*>(cinfo->dest); 64 d->mgr.init_destination = Mgr_init_destination_fcn; 65 d->mgr.empty_output_buffer = Mgr_empty_output_buffer_fcn; 66 d->mgr.term_destination = Mgr_term_destination_fcn; 67 d->outStream = new OutputStreamWrapper(); 68 if(d->outStream->init(env, outStream)) { 69 return J_SUCCESS; 70 } 71 return J_ERROR_FATAL; 72 } 73 74 void UpdateDstEnv(j_compress_ptr cinfo, JNIEnv* env) { 75 DestManager* d = reinterpret_cast<DestManager*>(cinfo->dest); 76 d->outStream->updateEnv(env); 77 } 78 79 void CleanDst(j_compress_ptr cinfo) { 80 if (cinfo != NULL && cinfo->dest != NULL) { 81 DestManager *d = reinterpret_cast<DestManager*>(cinfo->dest); 82 if (d->outStream != NULL) { 83 delete d->outStream; 84 d->outStream = NULL; 85 } 86 } 87 } 88 89 boolean Mgr_fill_input_buffer_fcn(j_decompress_ptr cinfo) { 90 SourceManager *src = reinterpret_cast<SourceManager*>(cinfo->src); 91 int32_t bytesRead = src->inStream->read(src->inStream->getBufferSize(), 0); 92 if (bytesRead == J_DONE) { 93 if (src->start_of_file == TRUE) { 94 ERREXIT(cinfo, JERR_INPUT_EMPTY); 95 } 96 WARNMS(cinfo, JWRN_JPEG_EOF); 97 bytesRead = src->inStream->forceReadEOI(); 98 } else if (bytesRead < 0) { 99 ERREXIT(cinfo, JERR_FILE_READ); 100 } else if (bytesRead == 0) { 101 LOGW("read 0 bytes from InputStream."); 102 } 103 src->mgr.next_input_byte = reinterpret_cast<JOCTET*>(src->inStream->getBufferPtr()); 104 src->mgr.bytes_in_buffer = bytesRead; 105 if (bytesRead != 0) { 106 src->start_of_file = FALSE; 107 } 108 return TRUE; 109 } 110 111 void Mgr_init_source_fcn(j_decompress_ptr cinfo) { 112 SourceManager *s = reinterpret_cast<SourceManager*>(cinfo->src); 113 s->start_of_file = TRUE; 114 Mgr_fill_input_buffer_fcn(cinfo); 115 } 116 117 void Mgr_skip_input_data_fcn(j_decompress_ptr cinfo, long num_bytes) { 118 // Cannot skip negative or 0 bytes. 119 if (num_bytes <= 0) { 120 LOGW("skipping 0 bytes in InputStream"); 121 return; 122 } 123 SourceManager *src = reinterpret_cast<SourceManager*>(cinfo->src); 124 if (src->mgr.bytes_in_buffer >= (size_t)num_bytes) { 125 src->mgr.bytes_in_buffer -= num_bytes; 126 src->mgr.next_input_byte += num_bytes; 127 } else { 128 // if skipping more bytes than remain in buffer, set skip_bytes 129 int64_t skip = num_bytes - src->mgr.bytes_in_buffer; 130 src->mgr.next_input_byte += src->mgr.bytes_in_buffer; 131 src->mgr.bytes_in_buffer = 0; 132 int64_t actual = src->inStream->skip(skip); 133 if (actual < 0) { 134 ERREXIT(cinfo, JERR_FILE_READ); 135 } 136 skip -= actual; 137 while (skip > 0) { 138 actual = src->inStream->skip(skip); 139 if (actual < 0) { 140 ERREXIT(cinfo, JERR_FILE_READ); 141 } 142 skip -= actual; 143 if (actual == 0) { 144 // Multiple zero byte skips, likely EOF 145 WARNMS(cinfo, JWRN_JPEG_EOF); 146 return; 147 } 148 } 149 } 150 } 151 152 void Mgr_term_source_fcn(j_decompress_ptr cinfo __unused) { 153 //noop 154 } 155 156 int32_t MakeSrc(j_decompress_ptr cinfo, JNIEnv *env, jobject inStream){ 157 if (cinfo->src != NULL) { 158 LOGE("SourceManager already exists, cannot allocate!"); 159 return J_ERROR_FATAL; 160 } else { 161 size_t size = sizeof(SourceManager); 162 cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) 163 ((j_common_ptr) cinfo, JPOOL_PERMANENT, size); 164 if (cinfo->src == NULL) { 165 // Could not allocate memory. 166 LOGE("Could not allocate memory for SourceManager."); 167 return J_ERROR_FATAL; 168 } 169 memset(cinfo->src, '0', size); 170 } 171 SourceManager *s = reinterpret_cast<SourceManager*>(cinfo->src); 172 s->start_of_file = TRUE; 173 s->mgr.init_source = Mgr_init_source_fcn; 174 s->mgr.fill_input_buffer = Mgr_fill_input_buffer_fcn; 175 s->mgr.skip_input_data = Mgr_skip_input_data_fcn; 176 s->mgr.resync_to_restart = jpeg_resync_to_restart; // use default restart 177 s->mgr.term_source = Mgr_term_source_fcn; 178 s->inStream = new InputStreamWrapper(); 179 if(s->inStream->init(env, inStream)) { 180 return J_SUCCESS; 181 } 182 return J_ERROR_FATAL; 183 } 184 185 void UpdateSrcEnv(j_decompress_ptr cinfo, JNIEnv* env) { 186 SourceManager* s = reinterpret_cast<SourceManager*>(cinfo->src); 187 s->inStream->updateEnv(env); 188 } 189 190 void CleanSrc(j_decompress_ptr cinfo) { 191 if (cinfo != NULL && cinfo->src != NULL) { 192 SourceManager *s = reinterpret_cast<SourceManager*>(cinfo->src); 193 if (s->inStream != NULL) { 194 delete s->inStream; 195 s->inStream = NULL; 196 } 197 } 198 } 199