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 #include "securec.h"
18
19 namespace OHOS {
20 namespace ImagePlugin {
21 using namespace OHOS::HiviewDFX;
22
23 static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "JpegUtils" };
24
25 // these functions are called by libjpeg-turbo third_party library, no need check input parameter.
26 // for error manager
ErrorExit(j_common_ptr dinfo)27 void ErrorExit(j_common_ptr dinfo)
28 {
29 if ((dinfo == nullptr) || (dinfo->err == nullptr)) {
30 return;
31 }
32 // dinfo->err really points to a ErrorMgr struct, so coerce pointer.
33 ErrorMgr *err = static_cast<ErrorMgr *>(dinfo->err);
34 (*dinfo->err->output_message)(dinfo);
35 // return control to the setjmp point.
36 longjmp(err->setjmp_buffer, SET_JUMP_VALUE);
37 }
38
OutputErrorMessage(j_common_ptr dinfo)39 void OutputErrorMessage(j_common_ptr dinfo)
40 {
41 if ((dinfo == nullptr) || (dinfo->err == nullptr)) {
42 return;
43 }
44 char buffer[JMSG_LENGTH_MAX] = { 0 };
45 dinfo->err->format_message(dinfo, buffer);
46 HiLog::Error(LABEL, "libjpeg error %{public}d <%{public}s>.", dinfo->err->msg_code, buffer);
47 }
48
49 // for source manager
50 // this is called by jpeg_read_header() before any data is actually read.
InitSrcStream(j_decompress_ptr dinfo)51 void InitSrcStream(j_decompress_ptr dinfo)
52 {
53 if ((dinfo == nullptr) || (dinfo->src == nullptr)) {
54 HiLog::Error(LABEL, "init source stream error.");
55 return;
56 }
57 JpegSrcMgr *src = static_cast<JpegSrcMgr *>(dinfo->src);
58 src->next_input_byte = src->streamData.inputStreamBuffer;
59 src->bytes_in_buffer = 0;
60 }
61
62 // this is called whenever bytes_in_buffer has reached zero and more data is wanted.
FillInputBuffer(j_decompress_ptr dinfo)63 boolean FillInputBuffer(j_decompress_ptr dinfo)
64 {
65 if (dinfo == nullptr) {
66 HiLog::Error(LABEL, "fill input buffer error, decompress struct is null.");
67 return FALSE;
68 }
69 JpegSrcMgr *src = static_cast<JpegSrcMgr *>(dinfo->src);
70 if ((src == nullptr) || (src->inputStream == nullptr)) {
71 HiLog::Error(LABEL, "fill input buffer error, source stream is null.");
72 ERREXIT(dinfo, JERR_FILE_READ);
73 return FALSE;
74 }
75
76 uint32_t preReadPos = src->inputStream->Tell();
77 if (!src->inputStream->IsStreamCompleted() && !src->inputStream->Seek(preReadPos + JPEG_BUFFER_SIZE)) {
78 return FALSE;
79 }
80 src->inputStream->Seek(preReadPos);
81 if (!src->inputStream->Read(src->bufferSize, src->streamData)) {
82 HiLog::Error(LABEL, "fill input buffer error, read source stream failed.");
83 return FALSE;
84 }
85 if (!src->inputStream->IsStreamCompleted() && src->streamData.dataSize < JPEG_BUFFER_SIZE) {
86 uint32_t curr = src->inputStream->Tell();
87 src->inputStream->Seek(curr - src->streamData.dataSize);
88 HiLog::Debug(LABEL, "fill input buffer seekTo=%{public}u, rewindSize=%{public}u.",
89 curr - src->streamData.dataSize, src->streamData.dataSize);
90 return FALSE;
91 }
92 src->next_input_byte = src->streamData.inputStreamBuffer;
93 src->bytes_in_buffer = src->streamData.dataSize;
94 return TRUE;
95 }
96
97 // skip num_bytes worth of data.
SkipInputData(j_decompress_ptr dinfo,long numBytes)98 void SkipInputData(j_decompress_ptr dinfo, long numBytes)
99 {
100 if (dinfo == nullptr) {
101 HiLog::Error(LABEL, "skip input buffer error, decompress struct is null.");
102 return;
103 }
104 JpegSrcMgr *src = static_cast<JpegSrcMgr *>(dinfo->src);
105 if ((src == nullptr) || (src->inputStream == nullptr)) {
106 HiLog::Error(LABEL, "skip input buffer error, source stream is null.");
107 ERREXIT(dinfo, JERR_FILE_READ);
108 return;
109 }
110 size_t bytes = static_cast<size_t>(numBytes);
111 if (bytes > src->bytes_in_buffer) {
112 size_t bytesToSkip = bytes - src->bytes_in_buffer;
113 uint32_t nowOffset = src->inputStream->Tell();
114 if (bytesToSkip > src->inputStream->GetStreamSize() - nowOffset) {
115 HiLog::Error(LABEL, "skip data:%{public}zu larger than current offset:%{public}u.", bytesToSkip, nowOffset);
116 return;
117 }
118 if (!src->inputStream->Seek(nowOffset + bytesToSkip)) {
119 HiLog::Error(LABEL, "skip data:%{public}zu fail, current offset:%{public}u.", bytesToSkip, nowOffset);
120 ERREXIT(dinfo, JERR_FILE_READ);
121 return;
122 }
123 src->next_input_byte = src->streamData.inputStreamBuffer;
124 src->bytes_in_buffer = 0;
125 } else {
126 src->next_input_byte += numBytes;
127 src->bytes_in_buffer -= numBytes;
128 }
129 }
130
131 // this is called by jpeg_finish_decompress() after all data has been read. Often a no-op.
TermSrcStream(j_decompress_ptr dinfo)132 void TermSrcStream(j_decompress_ptr dinfo)
133 {}
134
135 // for destination manager
136 // this is called by jpeg_start_compress() before any data is actually written.
InitDstStream(j_compress_ptr cinfo)137 void InitDstStream(j_compress_ptr cinfo)
138 {
139 if ((cinfo == nullptr) || (cinfo->dest == nullptr)) {
140 HiLog::Error(LABEL, "init destination stream error.");
141 return;
142 }
143 JpegDstMgr *dest = static_cast<JpegDstMgr *>(cinfo->dest);
144 dest->next_output_byte = dest->buffer;
145 dest->free_in_buffer = dest->bufferSize;
146 }
147
148 // this is called whenever the buffer has filled (free_in_buffer reaches zero).
EmptyOutputBuffer(j_compress_ptr cinfo)149 boolean EmptyOutputBuffer(j_compress_ptr cinfo)
150 {
151 if (cinfo == nullptr) {
152 HiLog::Error(LABEL, "write output buffer error, compress struct is null.");
153 return FALSE;
154 }
155 JpegDstMgr *dest = static_cast<JpegDstMgr *>(cinfo->dest);
156 if ((dest == nullptr) || (dest->outputStream == nullptr)) {
157 HiLog::Error(LABEL, "write output buffer error, dest stream is null.");
158 ERREXIT(cinfo, JERR_FILE_WRITE);
159 return FALSE;
160 }
161 if (!dest->outputStream->Write(dest->buffer, dest->bufferSize)) {
162 HiLog::Error(LABEL, "write output buffer error, write dest stream failed.");
163 ERREXIT(cinfo, JERR_FILE_WRITE);
164 return FALSE;
165 }
166 dest->next_output_byte = dest->buffer;
167 dest->free_in_buffer = dest->bufferSize;
168 return TRUE;
169 }
170
171 // this is called by jpeg_finish_compress() after all data has been written.
TermDstStream(j_compress_ptr cinfo)172 void TermDstStream(j_compress_ptr cinfo)
173 {
174 if (cinfo == nullptr) {
175 HiLog::Error(LABEL, "term output buffer error, compress struct is null.");
176 return;
177 }
178 JpegDstMgr *dest = static_cast<JpegDstMgr *>(cinfo->dest);
179 if ((dest == nullptr) || (dest->outputStream == nullptr)) {
180 HiLog::Error(LABEL, "term output buffer error, dest stream is null.");
181 ERREXIT(cinfo, JERR_FILE_WRITE);
182 return;
183 }
184 size_t size = dest->bufferSize - dest->free_in_buffer;
185 if (size > 0) {
186 if (!dest->outputStream->Write(dest->buffer, size)) {
187 HiLog::Error(LABEL, "term output buffer error, write dest stream size:%{public}zu failed.", size);
188 ERREXIT(cinfo, JERR_FILE_WRITE);
189 return;
190 }
191 }
192 dest->outputStream->Flush();
193 }
DoubleToString(double num)194 std::string DoubleToString(double num)
195 {
196 char str[256];
197 int32_t ret = sprintf_s(str, sizeof(str), "%lf", num);
198 if (ret <= PRINTF_SUCCESS) {
199 return "";
200 }
201 std::string result = str;
202 return result;
203 }
204 } // namespace ImagePlugin
205 } // namespace OHOS
206