2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "error_codes.h"
18 #include "jni_defines.h"
19 #include "jpeg_hook.h"
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();
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);
36 dst->mgr.next_output_byte = reinterpret_cast<JOCTET*>(dst->outStream->getBufferPtr());
37 dst->mgr.free_in_buffer = len;
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);
49 int32_t MakeDst(j_compress_ptr cinfo, JNIEnv *env, jobject outStream) {
50 if (cinfo->dest != NULL) {
51 LOGE("DestManager already exists, cannot allocate!");
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.");
61 memset(cinfo->dest, '0', size);
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)) {
74 void UpdateDstEnv(j_compress_ptr cinfo, JNIEnv* env) {
75 DestManager* d = reinterpret_cast<DestManager*>(cinfo->dest);
76 d->outStream->updateEnv(env);
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) {
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);
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.");
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;
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);
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");
123 SourceManager *src = reinterpret_cast<SourceManager*>(cinfo->src);
124 if (src->mgr.bytes_in_buffer >= num_bytes) {
125 src->mgr.bytes_in_buffer -= num_bytes;
126 src->mgr.next_input_byte += num_bytes;
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);
134 ERREXIT(cinfo, JERR_FILE_READ);
138 actual = src->inStream->skip(skip);
140 ERREXIT(cinfo, JERR_FILE_READ);
144 // Multiple zero byte skips, likely EOF
145 WARNMS(cinfo, JWRN_JPEG_EOF);
152 void Mgr_term_source_fcn(j_decompress_ptr cinfo) {
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;
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;
169 memset(cinfo->src, '0', size);
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)) {
182 return J_ERROR_FATAL;
185 void UpdateSrcEnv(j_decompress_ptr cinfo, JNIEnv* env) {
186 SourceManager* s = reinterpret_cast<SourceManager*>(cinfo->src);
187 s->inStream->updateEnv(env);
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) {