• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 "webp_exif_metadata_accessor.h"
17 
18 #include <libexif/exif-data.h>
19 
20 #include "file_metadata_stream.h"
21 #include "image_log.h"
22 #include "media_errors.h"
23 #include "tiff_parser.h"
24 
25 #undef LOG_DOMAIN
26 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
27 
28 #undef LOG_TAG
29 #define LOG_TAG "WebpExifMetadataAccessor"
30 
31 namespace OHOS {
32 namespace Media {
33 namespace {
34 byte WEBP_PAD_ODD = 0x00;
35 constexpr auto WEBP_RIFF_SIZE = 4;
36 constexpr auto WEBP_FILE_SIZE_BUFF_SIZE = 4;
37 constexpr auto WEBP_CHUNK_HEAD_SIZE = 12;
38 constexpr auto WEBP_CHUNK_ID_SIZE = 4;
39 constexpr auto WEBP_CHUNK_SIZE = 4;
40 constexpr auto WEBP_CHUNK_VP8X_SIZE = 18;
41 constexpr auto WEBP_EXIF_FLAG_BIT = 0x08;
42 constexpr auto WEBP_BYTE_BITS = 8;
43 constexpr auto WEBP_BUF_SIZE = 2;
44 constexpr auto WEBP_CHUNK_WIDTH_OFFSET = 6;
45 constexpr auto WEBP_CHUNK_HEIGHT_OFFSET = 8;
46 constexpr auto WEBP_VP8L_WIDTH_BIT = 0x3F;
47 constexpr auto WEBP_VP8L_HEIGHT_BIT = 0x3FU;
48 constexpr auto WEBP_VP8L_HEIGHT_BIT1 = 0xFU;
49 constexpr auto WEBP_CHUNK_HEADER_VP8X = "VP8X";
50 constexpr auto WEBP_CHUNK_HEADER_VP8 = "VP8 ";
51 constexpr auto WEBP_CHUNK_HEADER_VP8L = "VP8L";
52 constexpr auto WEBP_CHUNK_HEADER_ANMF = "ANMF";
53 constexpr auto WEBP_CHUNK_HEADER_EXIF = "EXIF";
54 constexpr auto WEBP_CHUNK_OPERATE_FLAG = 0xFF;
55 constexpr auto WEBP_WRITE_BLOCK = 4096 * 32;
56 constexpr auto WEBP_MAX_CHUNKDATA_SIZE = 300 * 1024 * 1024;
57 }
58 
WebpExifMetadataAccessor(std::shared_ptr<MetadataStream> & stream)59 WebpExifMetadataAccessor::WebpExifMetadataAccessor(std::shared_ptr<MetadataStream> &stream)
60     : AbstractExifMetadataAccessor(stream)
61 {}
62 
~WebpExifMetadataAccessor()63 WebpExifMetadataAccessor::~WebpExifMetadataAccessor() {}
64 
Read()65 uint32_t WebpExifMetadataAccessor::Read()
66 {
67     DataBuf dataBuf;
68     if (!ReadBlob(dataBuf)) {
69         IMAGE_LOGD("Image stream does not have dataBuf.");
70         return ERR_IMAGE_SOURCE_DATA;
71     }
72 
73     ExifData *exifData;
74     TiffParser::Decode(reinterpret_cast<const unsigned char *>(dataBuf.CData()), dataBuf.Size(), &exifData);
75     bool cond = exifData == nullptr;
76     CHECK_DEBUG_RETURN_RET_LOG(cond, ERR_IMAGE_DECODE_FAILED, "Image stream does not have exifData.");
77 
78     exifMetadata_ = std::make_shared<OHOS::Media::ExifMetadata>(exifData);
79 
80     return SUCCESS;
81 }
82 
ReadBlob(DataBuf & blob)83 bool WebpExifMetadataAccessor::ReadBlob(DataBuf &blob)
84 {
85     bool cond = false;
86     if (!imageStream_->IsOpen()) {
87         cond = !imageStream_->Open(OpenMode::ReadWrite);
88         CHECK_ERROR_RETURN_RET_LOG(cond, false, "Output image stream open failed.");
89     }
90     imageStream_->Seek(WEBP_CHUNK_HEAD_SIZE, SeekPos::BEGIN);
91 
92     Vp8xAndExifInfo exifFlag = Vp8xAndExifInfo::UNKNOWN;
93     if (!CheckChunkVp8x(exifFlag)) {
94         return false;
95     }
96 
97     while (!imageStream_->IsEof()) {
98         DataBuf chunkId(WEBP_CHUNK_ID_SIZE);
99         cond = static_cast<size_t>(imageStream_->Read(chunkId.Data(), chunkId.Size())) != chunkId.Size() ||
100                imageStream_->IsEof();
101         CHECK_ERROR_RETURN_RET_LOG(cond, false, "Image stream does not find chunkid.");
102 
103         DataBuf chunkSize(WEBP_CHUNK_SIZE);
104         cond = static_cast<size_t>(imageStream_->Read(chunkSize.Data(), chunkSize.Size())) != chunkSize.Size() ||
105                imageStream_->IsEof();
106         CHECK_ERROR_RETURN_RET_LOG(cond, false, "Image stream does not find chunk size.");
107         const uint32_t size = chunkSize.ReadUInt32(0, littleEndian);
108         const size_t imgSize = static_cast<size_t>(imageStream_->GetSize());
109         cond = size > imgSize - imageStream_->Tell();
110         CHECK_ERROR_RETURN_RET_LOG(cond, false, "Read chunk length error.");
111 
112         std::string strChunkId(reinterpret_cast<const char*>(chunkId.CData()), WEBP_CHUNK_ID_SIZE);
113         if (strChunkId != WEBP_CHUNK_HEADER_EXIF) {
114             imageStream_->Seek(size, SeekPos::CURRENT);
115             if (size % WEBP_BUF_SIZE) {
116                 imageStream_->Seek(1, SeekPos::CURRENT);
117             }
118             continue;
119         }
120 
121         blob.Resize(size);
122         imageStream_->Read(blob.Data(), size);
123         tiffOffset_ = imageStream_->Tell() - static_cast<long>(blob.Size());
124         return true;
125     }
126 
127     IMAGE_LOGE("Image stream does not find exif blob.");
128     return false;
129 }
130 
CheckChunkVp8x(Vp8xAndExifInfo & exifFlag) const131 bool WebpExifMetadataAccessor::CheckChunkVp8x(Vp8xAndExifInfo &exifFlag) const
132 {
133     DataBuf chunkId(WEBP_CHUNK_ID_SIZE);
134     bool cond = false;
135     cond = static_cast<size_t>(imageStream_->Read(chunkId.Data(), chunkId.Size())) != chunkId.Size() ||
136            imageStream_->IsEof();
137     CHECK_DEBUG_RETURN_RET_LOG(cond, false, "Image stream does not find vp8x.");
138 
139     std::string strChunkId(reinterpret_cast<const char *>(chunkId.CData()), WEBP_CHUNK_ID_SIZE);
140     if (strChunkId != WEBP_CHUNK_HEADER_VP8X) {
141         exifFlag = Vp8xAndExifInfo::VP8X_NOT_EXIST;
142         IMAGE_LOGD("Image stream does not find vp8x.");
143         return false;
144     }
145 
146     byte chunkSize[WEBP_CHUNK_ID_SIZE];
147     cond = static_cast<size_t>(imageStream_->Read(chunkSize, WEBP_CHUNK_SIZE)) != WEBP_CHUNK_SIZE ||
148            imageStream_->IsEof();
149     CHECK_ERROR_RETURN_RET_LOG(cond, false, "Image stream does not find vp8x size.");
150     const uint32_t size = GetULong(chunkSize, littleEndian);
151     cond = size > WEBP_MAX_CHUNKDATA_SIZE;
152     CHECK_ERROR_RETURN_RET_LOG(cond, false, "Image stream chunkdata size is too large.");
153     DataBuf chunkData(size);
154     CHECK_ERROR_RETURN_RET_LOG(size == 0 || chunkData.Empty() || chunkData.Data() == nullptr,
155         false, "Image stream does not find vp8x data.");
156 
157     cond = static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size() ||
158            imageStream_->IsEof();
159     CHECK_ERROR_RETURN_RET_LOG(cond, false, "Image stream does not find vp8x data.");
160 
161     byte reserved = chunkData.Data()[0];
162     if (!(reserved & WEBP_EXIF_FLAG_BIT)) {
163         exifFlag = Vp8xAndExifInfo::EXIF_NOT_EXIST;
164         IMAGE_LOGD("Image stream does not have exifData.");
165         return false;
166     }
167     exifFlag = Vp8xAndExifInfo::EXIF_EXIST;
168     return true;
169 }
170 
Write()171 uint32_t WebpExifMetadataAccessor::Write()
172 {
173     uint8_t *dataBlob = nullptr;
174     uint32_t size = 0;
175     if (!GetExifEncodeBlob(&dataBlob, size)) {
176         IMAGE_LOGE("Encode Metadata failed.");
177         return ERR_MEDIA_VALUE_INVALID;
178     }
179 
180     uint32_t result = UpdateData(dataBlob, size);
181 
182     if (dataBlob != nullptr) {
183         free(dataBlob);
184         dataBlob = nullptr;
185     }
186 
187     return result;
188 }
189 
GetExifEncodeBlob(uint8_t ** dataBlob,uint32_t & size)190 bool WebpExifMetadataAccessor::GetExifEncodeBlob(uint8_t **dataBlob, uint32_t &size)
191 {
192     if (this->Get() == nullptr) {
193         IMAGE_LOGE("Exif blob empty.");
194         return false;
195     }
196 
197     ExifData *exifData = this->Get()->GetExifData();
198     TiffParser::Encode(dataBlob, size, exifData);
199 
200     bool cond = dataBlob == nullptr || *dataBlob == nullptr;
201     CHECK_ERROR_RETURN_RET_LOG(cond, false, "Encode webp data failed.");
202 
203     return (size > 0);
204 }
205 
WriteBlob(DataBuf & blob)206 uint32_t WebpExifMetadataAccessor::WriteBlob(DataBuf &blob)
207 {
208     byte *dataBlob = nullptr;
209     uint32_t size = 0;
210     if (!GetExifBlob(blob, &dataBlob, size)) {
211         IMAGE_LOGE("Blob data empty.");
212         return ERR_MEDIA_VALUE_INVALID;
213     }
214 
215     return UpdateData(dataBlob, size);
216 }
217 
GetExifBlob(const DataBuf & blob,uint8_t ** dataBlob,uint32_t & size)218 bool WebpExifMetadataAccessor::GetExifBlob(const DataBuf &blob, uint8_t **dataBlob, uint32_t &size)
219 {
220     if (blob.Empty()) {
221         IMAGE_LOGE("Image exif blob data empty.");
222         return false;
223     }
224 
225     *dataBlob = const_cast<byte *>(blob.CData());
226     size = blob.Size();
227 
228     return true;
229 }
230 
UpdateData(uint8_t * dataBlob,uint32_t size)231 uint32_t WebpExifMetadataAccessor::UpdateData(uint8_t *dataBlob, uint32_t size)
232 {
233     BufferMetadataStream tmpBufStream;
234     bool cond = false;
235     cond = !tmpBufStream.Open(OpenMode::ReadWrite);
236     CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_SOURCE_DATA, "Image temp stream open failed.");
237 
238     cond = !imageStream_->IsOpen();
239     CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_SOURCE_DATA, "Output image stream not open.");
240 
241     cond = !UpdateExifMetadata(tmpBufStream, dataBlob, size);
242     CHECK_ERROR_RETURN_RET_LOG(cond, ERROR, "Image temp stream write failed.");
243 
244     imageStream_->Seek(0, SeekPos::BEGIN);
245     cond = !imageStream_->CopyFrom(tmpBufStream);
246     CHECK_ERROR_RETURN_RET_LOG(cond, ERR_MEDIA_INVALID_OPERATION, "Copy from temp stream failed");
247     return SUCCESS;
248 }
249 
UpdateExifMetadata(BufferMetadataStream & bufStream,uint8_t * dataBlob,uint32_t size)250 bool WebpExifMetadataAccessor::UpdateExifMetadata(BufferMetadataStream &bufStream, uint8_t *dataBlob, uint32_t size)
251 {
252     Vp8xAndExifInfo exifFlag = Vp8xAndExifInfo::UNKNOWN;
253     bool cond = false;
254     cond = !WriteHeader(bufStream, size, exifFlag);
255     CHECK_ERROR_RETURN_RET_LOG(cond, false, "Output image stream write header failed.");
256 
257     imageStream_->Seek(WEBP_CHUNK_HEAD_SIZE, SeekPos::BEGIN);
258     cond = !WirteChunkVp8x(bufStream, exifFlag);
259     CHECK_ERROR_RETURN_RET_LOG(cond, false, "Output image stream write vp8x failed.");
260 
261     if (exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST || exifFlag == Vp8xAndExifInfo::EXIF_NOT_EXIST) {
262         return InsertExifMetadata(bufStream, dataBlob, size);
263     }
264 
265     while (!imageStream_->IsEof()) {
266         DataBuf chunkHead(WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE);
267         cond = static_cast<size_t>(imageStream_->Read(chunkHead.Data(), chunkHead.Size())) != chunkHead.Size() ||
268                imageStream_->IsEof();
269         CHECK_ERROR_RETURN_RET_LOG(cond, false, "Failed to read image chunk header information.");
270 
271         uint32_t chunkSize = chunkHead.ReadUInt32(WEBP_CHUNK_ID_SIZE, littleEndian);
272         const ssize_t imgSize = imageStream_->GetSize();
273         cond = chunkSize > imgSize - imageStream_->Tell();
274         CHECK_ERROR_RETURN_RET_LOG(cond, false, "Read chunk length error.");
275 
276         if (chunkSize % WEBP_BUF_SIZE) {
277             ++chunkSize;
278         }
279 
280         DataBuf chunkData(chunkSize);
281         cond = static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size();
282         CHECK_ERROR_RETURN_RET_LOG(cond, false, "Failed to read image chunk data.");
283 
284         std::string strChunkId(reinterpret_cast<const char *>(chunkHead.CData()), WEBP_CHUNK_ID_SIZE);
285         if (strChunkId == WEBP_CHUNK_HEADER_EXIF) {
286             UL2Data(chunkHead.Data(WEBP_FILE_SIZE_BUFF_SIZE), size, littleEndian);
287             bufStream.Write(chunkHead.Data(), chunkHead.Size());
288             bufStream.Write(dataBlob, size);
289             if (size % WEBP_BUF_SIZE) {
290                 bufStream.Write(&WEBP_PAD_ODD, 1);
291             }
292             break;
293         }
294 
295         bufStream.Write(chunkHead.Data(), chunkHead.Size());
296         bufStream.Write(chunkData.Data(), chunkData.Size());
297     }
298 
299     return CopyRestData(bufStream);
300 }
301 
InsertExifMetadata(BufferMetadataStream & bufStream,uint8_t * dataBlob,uint32_t size)302 bool WebpExifMetadataAccessor::InsertExifMetadata(BufferMetadataStream &bufStream, uint8_t *dataBlob, uint32_t size)
303 {
304     bool cond = !CopyRestData(bufStream);
305     CHECK_ERROR_RETURN_RET(cond, false);
306 
307     static byte exifChunckId[] = { 0x45, 0x58, 0x49, 0x46 };
308     if (bufStream.Write(exifChunckId, WEBP_CHUNK_ID_SIZE) != WEBP_CHUNK_ID_SIZE) {
309         IMAGE_LOGE("BufStream tell: %{public}lu", bufStream.Tell());
310         return false;
311     }
312     DataBuf exifChunckSize(WEBP_CHUNK_SIZE);
313     UL2Data(exifChunckSize.Data(), size, littleEndian);
314     if (bufStream.Write(exifChunckSize.Data(), exifChunckSize.Size()) != (ssize_t)exifChunckSize.Size() ||
315         bufStream.Write(dataBlob, size) != size) {
316         return false;
317     }
318     if (size % WEBP_BUF_SIZE) {
319         bufStream.Write(&WEBP_PAD_ODD, 1);
320     }
321     return true;
322 }
323 
GetImageWidthAndHeight()324 std::tuple<uint32_t, uint32_t> WebpExifMetadataAccessor::GetImageWidthAndHeight()
325 {
326     while (!imageStream_->IsEof()) {
327         DataBuf chunkHead(WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE);
328         if (static_cast<size_t>(imageStream_->Read(chunkHead.Data(), chunkHead.Size())) != chunkHead.Size() ||
329             imageStream_->IsEof()) {
330             IMAGE_LOGE("Failed to read image chunk header information.");
331             return std::make_tuple(0, 0);
332         }
333 
334         const uint32_t size = chunkHead.ReadUInt32(WEBP_CHUNK_ID_SIZE, littleEndian);
335         const ssize_t imgSize = imageStream_->GetSize();
336         if (size > imgSize - imageStream_->Tell()) {
337             IMAGE_LOGE("Read chunk length error.");
338             return std::make_tuple(0, 0);
339         }
340 
341         DataBuf chunkData(size);
342         if (static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size()) {
343             IMAGE_LOGE("Failed to read image chunk data.");
344             return std::make_tuple(0, 0);
345         }
346 
347         std::string strChunkId(reinterpret_cast<const char *>(chunkHead.CData()), WEBP_CHUNK_ID_SIZE);
348         if (strChunkId == WEBP_CHUNK_HEADER_VP8 || strChunkId == WEBP_CHUNK_HEADER_VP8L ||
349             strChunkId == WEBP_CHUNK_HEADER_ANMF) {
350             return GetWidthAndHeightFormChunk(strChunkId, chunkData);
351         }
352     }
353     return std::make_tuple(0, 0);
354 }
355 
GetWidthAndHeightFormChunk(const std::string & strChunkId,const DataBuf & chunkData)356 std::tuple<uint32_t, uint32_t> WebpExifMetadataAccessor::GetWidthAndHeightFormChunk(const std::string &strChunkId,
357     const DataBuf &chunkData)
358 {
359     uint32_t width = 0;
360     uint32_t height = 0;
361     static const uint32_t bitOperVp8 = 0x3fff;
362     static const byte offset3 = 3;
363     static const byte offset2 = 2;
364     if (strChunkId == WEBP_CHUNK_HEADER_VP8 && chunkData.Size() >= (WEBP_CHUNK_HEIGHT_OFFSET + WEBP_BUF_SIZE)) {
365         byte sizeBuf[WEBP_BUF_SIZE];
366 
367         (void)memcpy_s(&sizeBuf, WEBP_BUF_SIZE, chunkData.CData(WEBP_CHUNK_WIDTH_OFFSET), WEBP_BUF_SIZE);
368         width = GetUShort(sizeBuf, littleEndian) & bitOperVp8;
369         (void)memcpy_s(&sizeBuf, WEBP_BUF_SIZE, chunkData.CData(WEBP_CHUNK_HEIGHT_OFFSET), WEBP_BUF_SIZE);
370         height = GetUShort(sizeBuf, littleEndian) & bitOperVp8;
371         return std::make_tuple(width, height);
372     }
373 
374     if (strChunkId == WEBP_CHUNK_HEADER_VP8L && chunkData.Size() >= (WEBP_BUF_SIZE + WEBP_BUF_SIZE + 1)) {
375         byte bufWidth[WEBP_BUF_SIZE];
376         byte bufHeight[WEBP_BUF_SIZE + 1];
377 
378         (void)memcpy_s(&bufWidth, WEBP_BUF_SIZE, chunkData.CData(1), WEBP_BUF_SIZE);
379         bufWidth[1] &= WEBP_VP8L_WIDTH_BIT;
380         width = GetUShort(bufWidth, littleEndian) + 1;
381         (void)memcpy_s(&bufHeight, WEBP_BUF_SIZE + 1, chunkData.CData(WEBP_BUF_SIZE), WEBP_BUF_SIZE + 1);
382         bufHeight[0] = ((bufHeight[0] >> WEBP_CHUNK_WIDTH_OFFSET) & offset3) |
383             ((bufHeight[1] & WEBP_VP8L_HEIGHT_BIT) << offset2);
384         bufHeight[1] = ((bufHeight[1] >> WEBP_CHUNK_WIDTH_OFFSET) & offset3) |
385             ((bufHeight[WEBP_BUF_SIZE] & WEBP_VP8L_HEIGHT_BIT1) << offset2);
386         height = GetUShort(bufHeight, littleEndian) + 1;
387         return std::make_tuple(width, height);
388     }
389 
390     if (strChunkId == WEBP_CHUNK_HEADER_ANMF && chunkData.Size() >= (WEBP_CHUNK_WIDTH_OFFSET + offset3 + offset3)) {
391         byte sizeBuf[WEBP_CHUNK_SIZE];
392 
393         (void)memcpy_s(&sizeBuf, offset3, chunkData.CData(WEBP_CHUNK_WIDTH_OFFSET), offset3);
394         sizeBuf[offset3] = 0;
395         width = GetULong(sizeBuf, littleEndian) + 1;
396         (void)memcpy_s(&sizeBuf, offset3, chunkData.CData(WEBP_CHUNK_WIDTH_OFFSET + offset3), offset3);
397         sizeBuf[offset3] = 0;
398         height = GetULong(sizeBuf, littleEndian) + 1;
399         return std::make_tuple(width, height);
400     }
401     return std::make_tuple(width, height);
402 }
403 
CopyRestData(BufferMetadataStream & bufStream)404 bool WebpExifMetadataAccessor::CopyRestData(BufferMetadataStream &bufStream)
405 {
406     DataBuf buf(WEBP_WRITE_BLOCK);
407     ssize_t readSize = imageStream_->Read(buf.Data(), buf.Size());
408     while (readSize > 0) {
409         if (bufStream.Write(buf.Data(), readSize) != readSize) {
410             IMAGE_LOGE("Write block data to temp stream failed.");
411             return false;
412         }
413         readSize = imageStream_->Read(buf.Data(), buf.Size());
414     }
415 
416     return true;
417 }
418 
WriteHeader(BufferMetadataStream & bufStream,uint32_t size,Vp8xAndExifInfo & exifFlag)419 bool WebpExifMetadataAccessor::WriteHeader(BufferMetadataStream &bufStream, uint32_t size, Vp8xAndExifInfo &exifFlag)
420 {
421     DataBuf headInfo(WEBP_CHUNK_HEAD_SIZE);
422     imageStream_->Seek(0, SeekPos::BEGIN);
423     bool cond = false;
424     cond = static_cast<size_t>(imageStream_->Read(headInfo.Data(), headInfo.Size())) != headInfo.Size() ||
425            imageStream_->IsEof();
426     CHECK_ERROR_RETURN_RET(cond, false);
427     uint32_t fileSize = GetULong(headInfo.Data(WEBP_RIFF_SIZE), littleEndian) + size;
428     if (size % WEBP_BUF_SIZE) {
429         ++fileSize;
430     }
431 
432     cond = !CheckChunkVp8x(exifFlag) && exifFlag == Vp8xAndExifInfo::UNKNOWN;
433     CHECK_ERROR_RETURN_RET(cond, false);
434 
435     if (exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST || exifFlag == Vp8xAndExifInfo::EXIF_NOT_EXIST) {
436         fileSize += exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST ? WEBP_CHUNK_VP8X_SIZE : 0;
437         fileSize += WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE;
438         UL2Data(headInfo.Data(WEBP_FILE_SIZE_BUFF_SIZE), fileSize, littleEndian);
439         IMAGE_LOGD("Write webp file size: %{public}u, new exif size: %{public}u", fileSize, size);
440         return bufStream.Write(headInfo.Data(), headInfo.Size()) == (ssize_t)headInfo.Size();
441     }
442 
443     DataBuf exifData;
444     cond = !ReadBlob(exifData);
445     CHECK_ERROR_RETURN_RET(cond, false);
446 
447     fileSize -= (exifData.Size() % WEBP_BUF_SIZE) ? (exifData.Size() + 1) : exifData.Size();
448     UL2Data(headInfo.Data(WEBP_FILE_SIZE_BUFF_SIZE), fileSize, littleEndian);
449     IMAGE_LOGD("Write webp file size: %{public}u, old exif size: %{public}u, new exif size: %{public}lu",
450         fileSize, size, static_cast<unsigned long>(exifData.Size()));
451     return bufStream.Write(headInfo.Data(), headInfo.Size()) == (ssize_t)headInfo.Size();
452 }
453 
WirteChunkVp8x(BufferMetadataStream & bufStream,const Vp8xAndExifInfo & exifFlag)454 bool WebpExifMetadataAccessor::WirteChunkVp8x(BufferMetadataStream &bufStream, const Vp8xAndExifInfo &exifFlag)
455 {
456     bool cond = false;
457     if (exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST) {
458         auto [width, height] = GetImageWidthAndHeight();
459         imageStream_->Seek(WEBP_CHUNK_HEAD_SIZE, SeekPos::BEGIN);
460         cond = width <= 0 || height <= 0;
461         CHECK_ERROR_RETURN_RET(cond, false);
462         static byte chunckHeader[] = { 0x56, 0x50, 0x38, 0x58, 0x0a, 0x00, 0x00, 0x00, 0x08,
463                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
464         size_t offset = WEBP_CHUNK_HEAD_SIZE;
465         uint32_t w = width - 1;
466         chunckHeader[offset] = w & WEBP_CHUNK_OPERATE_FLAG;
467         chunckHeader[++offset] = (w >> WEBP_BYTE_BITS) & WEBP_CHUNK_OPERATE_FLAG;
468         chunckHeader[++offset] = (w >> (WEBP_BYTE_BITS + WEBP_BYTE_BITS)) & WEBP_CHUNK_OPERATE_FLAG;
469 
470         uint32_t h = height - 1;
471         chunckHeader[++offset] = h & WEBP_CHUNK_OPERATE_FLAG;
472         chunckHeader[++offset] = (h >> WEBP_BYTE_BITS) & WEBP_CHUNK_OPERATE_FLAG;
473         chunckHeader[++offset] = (h >> (WEBP_BYTE_BITS + WEBP_BYTE_BITS)) & WEBP_CHUNK_OPERATE_FLAG;
474         return bufStream.Write(chunckHeader, WEBP_CHUNK_VP8X_SIZE) == WEBP_CHUNK_VP8X_SIZE;
475     }
476 
477     DataBuf chunkHead(WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE);
478     cond = static_cast<size_t>(imageStream_->Read(chunkHead.Data(), chunkHead.Size())) != chunkHead.Size();
479     CHECK_ERROR_RETURN_RET(cond, false);
480     if (bufStream.Write(chunkHead.Data(), chunkHead.Size()) != (ssize_t)chunkHead.Size()) {
481         return false;
482     }
483 
484     const uint32_t size = chunkHead.ReadUInt32(WEBP_CHUNK_ID_SIZE, littleEndian);
485     DataBuf chunkData(size);
486     if (static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size()) {
487         return false;
488     }
489     cond = chunkData.Data() == nullptr;
490     CHECK_ERROR_RETURN_RET(cond, false);
491     chunkData.Data()[0] |= WEBP_EXIF_FLAG_BIT;
492     return bufStream.Write(chunkData.Data(), chunkData.Size()) == (ssize_t)chunkData.Size();
493 }
494 } // namespace Media
495 } // namespace OHOS