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
Mgr_init_destination_fcn(j_compress_ptr cinfo)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
Mgr_empty_output_buffer_fcn(j_compress_ptr cinfo)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
Mgr_term_destination_fcn(j_compress_ptr cinfo)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
MakeDst(j_compress_ptr cinfo,JNIEnv * env,jobject outStream)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
UpdateDstEnv(j_compress_ptr cinfo,JNIEnv * env)74 void UpdateDstEnv(j_compress_ptr cinfo, JNIEnv* env) {
75 DestManager* d = reinterpret_cast<DestManager*>(cinfo->dest);
76 d->outStream->updateEnv(env);
77 }
78
CleanDst(j_compress_ptr cinfo)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
Mgr_fill_input_buffer_fcn(j_decompress_ptr cinfo)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
Mgr_init_source_fcn(j_decompress_ptr cinfo)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
Mgr_skip_input_data_fcn(j_decompress_ptr cinfo,long num_bytes)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
Mgr_term_source_fcn(j_decompress_ptr cinfo __unused)152 void Mgr_term_source_fcn(j_decompress_ptr cinfo __unused) {
153 //noop
154 }
155
MakeSrc(j_decompress_ptr cinfo,JNIEnv * env,jobject inStream)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
UpdateSrcEnv(j_decompress_ptr cinfo,JNIEnv * env)185 void UpdateSrcEnv(j_decompress_ptr cinfo, JNIEnv* env) {
186 SourceManager* s = reinterpret_cast<SourceManager*>(cinfo->src);
187 s->inStream->updateEnv(env);
188 }
189
CleanSrc(j_decompress_ptr cinfo)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