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