1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "jpeg_utils.h"
17
18 #include "image_log.h"
19 #include "securec.h"
20
21 #undef LOG_DOMAIN
22 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
23
24 #undef LOG_TAG
25 #define LOG_TAG "JpegUtils"
26
27 namespace OHOS {
28 namespace ImagePlugin {
29
30 // these functions are called by libjpeg-turbo third_party library, no need check input parameter.
31 // for error manager
ErrorExit(j_common_ptr dinfo)32 void ErrorExit(j_common_ptr dinfo)
33 {
34 if ((dinfo == nullptr) || (dinfo->err == nullptr)) {
35 return;
36 }
37 // dinfo->err really points to a ErrorMgr struct, so coerce pointer.
38 ErrorMgr *err = static_cast<ErrorMgr *>(dinfo->err);
39 (*dinfo->err->output_message)(dinfo);
40 // return control to the setjmp point.
41 longjmp(err->setjmp_buffer, SET_JUMP_VALUE);
42 }
43
OutputErrorMessage(j_common_ptr dinfo)44 void OutputErrorMessage(j_common_ptr dinfo) __attribute__((no_sanitize("cfi")))
45 {
46 if ((dinfo == nullptr) || (dinfo->err == nullptr)) {
47 return;
48 }
49 char buffer[JMSG_LENGTH_MAX] = { 0 };
50 dinfo->err->format_message(dinfo, buffer);
51 IMAGE_LOGE("libjpeg error %{public}d <%{public}s>.", dinfo->err->msg_code, buffer);
52 }
53
54 // for source manager
55 // this is called by jpeg_read_header() before any data is actually read.
InitSrcStream(j_decompress_ptr dinfo)56 void InitSrcStream(j_decompress_ptr dinfo) __attribute__((no_sanitize("cfi")))
57 {
58 if ((dinfo == nullptr) || (dinfo->src == nullptr)) {
59 IMAGE_LOGE("init source stream error.");
60 return;
61 }
62 JpegSrcMgr *src = static_cast<JpegSrcMgr *>(dinfo->src);
63 src->next_input_byte = src->streamData.inputStreamBuffer;
64 src->bytes_in_buffer = 0;
65 }
66
67 // this is called whenever bytes_in_buffer has reached zero and more data is wanted.
FillInputBuffer(j_decompress_ptr dinfo)68 boolean FillInputBuffer(j_decompress_ptr dinfo)
69 {
70 if (dinfo == nullptr) {
71 IMAGE_LOGE("fill input buffer error, decompress struct is null.");
72 return FALSE;
73 }
74 JpegSrcMgr *src = static_cast<JpegSrcMgr *>(dinfo->src);
75 if ((src == nullptr) || (src->inputStream == nullptr)) {
76 IMAGE_LOGE("fill input buffer error, source stream is null.");
77 ERREXIT(dinfo, JERR_FILE_READ);
78 return FALSE;
79 }
80
81 uint32_t preReadPos = src->inputStream->Tell();
82 if (!src->inputStream->IsStreamCompleted() && !src->inputStream->Seek(preReadPos + JPEG_BUFFER_SIZE)) {
83 return FALSE;
84 }
85 src->inputStream->Seek(preReadPos);
86 if (!src->inputStream->Read(src->bufferSize, src->streamData)) {
87 IMAGE_LOGE("fill input buffer error, read source stream failed.");
88 return FALSE;
89 }
90 if (!src->inputStream->IsStreamCompleted() && src->streamData.dataSize < JPEG_BUFFER_SIZE) {
91 uint32_t curr = src->inputStream->Tell();
92 src->inputStream->Seek(curr - src->streamData.dataSize);
93 IMAGE_LOGD("fill input buffer seekTo=%{public}u, rewindSize=%{public}u.",
94 curr - src->streamData.dataSize, src->streamData.dataSize);
95 return FALSE;
96 }
97 src->next_input_byte = src->streamData.inputStreamBuffer;
98 src->bytes_in_buffer = src->streamData.dataSize;
99 return TRUE;
100 }
101
102 // skip num_bytes worth of data.
SkipInputData(j_decompress_ptr dinfo,long numBytes)103 void SkipInputData(j_decompress_ptr dinfo, long numBytes)
104 {
105 if (dinfo == nullptr) {
106 IMAGE_LOGE("skip input buffer error, decompress struct is null.");
107 return;
108 }
109 JpegSrcMgr *src = static_cast<JpegSrcMgr *>(dinfo->src);
110 if ((src == nullptr) || (src->inputStream == nullptr)) {
111 IMAGE_LOGE("skip input buffer error, source stream is null.");
112 ERREXIT(dinfo, JERR_FILE_READ);
113 return;
114 }
115 size_t bytes = static_cast<size_t>(numBytes);
116 if (bytes > src->bytes_in_buffer) {
117 size_t bytesToSkip = bytes - src->bytes_in_buffer;
118 uint32_t nowOffset = src->inputStream->Tell();
119 if (bytesToSkip > src->inputStream->GetStreamSize() - nowOffset) {
120 IMAGE_LOGE("skip data:%{public}zu larger than current offset:%{public}u.", bytesToSkip, nowOffset);
121 return;
122 }
123 if (!src->inputStream->Seek(nowOffset + bytesToSkip)) {
124 IMAGE_LOGE("skip data:%{public}zu fail, current offset:%{public}u.", bytesToSkip, nowOffset);
125 ERREXIT(dinfo, JERR_FILE_READ);
126 return;
127 }
128 src->next_input_byte = src->streamData.inputStreamBuffer;
129 src->bytes_in_buffer = 0;
130 } else {
131 src->next_input_byte += numBytes;
132 src->bytes_in_buffer -= numBytes;
133 }
134 }
135
136 // this is called by jpeg_finish_decompress() after all data has been read. Often a no-op.
TermSrcStream(j_decompress_ptr dinfo)137 void TermSrcStream(j_decompress_ptr dinfo)
138 {}
139
140 // for destination manager
141 // this is called by jpeg_start_compress() before any data is actually written.
InitDstStream(j_compress_ptr cinfo)142 void InitDstStream(j_compress_ptr cinfo)
143 {
144 if ((cinfo == nullptr) || (cinfo->dest == nullptr)) {
145 IMAGE_LOGE("init destination stream error.");
146 return;
147 }
148 JpegDstMgr *dest = static_cast<JpegDstMgr *>(cinfo->dest);
149 dest->next_output_byte = dest->buffer;
150 dest->free_in_buffer = dest->bufferSize;
151 }
152
153 // this is called whenever the buffer has filled (free_in_buffer reaches zero).
EmptyOutputBuffer(j_compress_ptr cinfo)154 boolean EmptyOutputBuffer(j_compress_ptr cinfo)
155 {
156 if (cinfo == nullptr) {
157 IMAGE_LOGE("write output buffer error, compress struct is null.");
158 return FALSE;
159 }
160 JpegDstMgr *dest = static_cast<JpegDstMgr *>(cinfo->dest);
161 if ((dest == nullptr) || (dest->outputStream == nullptr)) {
162 IMAGE_LOGE("write output buffer error, dest stream is null.");
163 ERREXIT(cinfo, JERR_FILE_WRITE);
164 return FALSE;
165 }
166 if (!dest->outputStream->Write(dest->buffer, dest->bufferSize)) {
167 IMAGE_LOGE("write output buffer error, write dest stream failed.");
168 ERREXIT(cinfo, JERR_FILE_WRITE);
169 return FALSE;
170 }
171 dest->next_output_byte = dest->buffer;
172 dest->free_in_buffer = dest->bufferSize;
173 return TRUE;
174 }
175
176 // this is called by jpeg_finish_compress() after all data has been written.
TermDstStream(j_compress_ptr cinfo)177 void TermDstStream(j_compress_ptr cinfo)
178 {
179 if (cinfo == nullptr) {
180 IMAGE_LOGE("term output buffer error, compress struct is null.");
181 return;
182 }
183 JpegDstMgr *dest = static_cast<JpegDstMgr *>(cinfo->dest);
184 if ((dest == nullptr) || (dest->outputStream == nullptr)) {
185 IMAGE_LOGE("term output buffer error, dest stream is null.");
186 ERREXIT(cinfo, JERR_FILE_WRITE);
187 return;
188 }
189 size_t size = dest->bufferSize - dest->free_in_buffer;
190 if (size > 0) {
191 if (!dest->outputStream->Write(dest->buffer, size)) {
192 IMAGE_LOGE("term output buffer error, write dest stream size:%{public}zu failed.", size);
193 ERREXIT(cinfo, JERR_FILE_WRITE);
194 return;
195 }
196 }
197 dest->outputStream->Flush();
198 }
DoubleToString(double num)199 std::string DoubleToString(double num)
200 {
201 char str[256];
202 int32_t ret = sprintf_s(str, sizeof(str), "%lf", num);
203 if (ret <= 0) {
204 return "";
205 }
206 std::string result = str;
207 return result;
208 }
209 } // namespace ImagePlugin
210 } // namespace OHOS
211