• 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     if (size == 0 || chunkData.Empty() || chunkData.Data() == nullptr) {
155         IMAGE_LOGE("Image stream does not find vp8x data.");
156         return false;
157     }
158 
159     cond = static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size() ||
160            imageStream_->IsEof();
161     CHECK_ERROR_RETURN_RET_LOG(cond, false, "Image stream does not find vp8x data.");
162 
163     byte reserved = chunkData.Data()[0];
164     if (!(reserved & WEBP_EXIF_FLAG_BIT)) {
165         exifFlag = Vp8xAndExifInfo::EXIF_NOT_EXIST;
166         IMAGE_LOGD("Image stream does not have exifData.");
167         return false;
168     }
169     exifFlag = Vp8xAndExifInfo::EXIF_EXIST;
170     return true;
171 }
172 
Write()173 uint32_t WebpExifMetadataAccessor::Write()
174 {
175     uint8_t *dataBlob = nullptr;
176     uint32_t size = 0;
177     if (!GetExifEncodeBlob(&dataBlob, size)) {
178         IMAGE_LOGE("Encode Metadata failed.");
179         return ERR_MEDIA_VALUE_INVALID;
180     }
181 
182     uint32_t result = UpdateData(dataBlob, size);
183 
184     if (dataBlob != nullptr) {
185         free(dataBlob);
186         dataBlob = nullptr;
187     }
188 
189     return result;
190 }
191 
GetExifEncodeBlob(uint8_t ** dataBlob,uint32_t & size)192 bool WebpExifMetadataAccessor::GetExifEncodeBlob(uint8_t **dataBlob, uint32_t &size)
193 {
194     if (this->Get() == nullptr) {
195         IMAGE_LOGE("Exif blob empty.");
196         return false;
197     }
198 
199     ExifData *exifData = this->Get()->GetExifData();
200     TiffParser::Encode(dataBlob, size, exifData);
201 
202     bool cond = dataBlob == nullptr || *dataBlob == nullptr;
203     CHECK_ERROR_RETURN_RET_LOG(cond, false, "Encode webp data failed.");
204 
205     return (size > 0);
206 }
207 
WriteBlob(DataBuf & blob)208 uint32_t WebpExifMetadataAccessor::WriteBlob(DataBuf &blob)
209 {
210     byte *dataBlob = nullptr;
211     uint32_t size = 0;
212     if (!GetExifBlob(blob, &dataBlob, size)) {
213         IMAGE_LOGE("Blob data empty.");
214         return ERR_MEDIA_VALUE_INVALID;
215     }
216 
217     return UpdateData(dataBlob, size);
218 }
219 
GetExifBlob(const DataBuf & blob,uint8_t ** dataBlob,uint32_t & size)220 bool WebpExifMetadataAccessor::GetExifBlob(const DataBuf &blob, uint8_t **dataBlob, uint32_t &size)
221 {
222     if (blob.Empty()) {
223         IMAGE_LOGE("Image exif blob data empty.");
224         return false;
225     }
226 
227     *dataBlob = const_cast<byte *>(blob.CData());
228     size = blob.Size();
229 
230     return true;
231 }
232 
UpdateData(uint8_t * dataBlob,uint32_t size)233 uint32_t WebpExifMetadataAccessor::UpdateData(uint8_t *dataBlob, uint32_t size)
234 {
235     BufferMetadataStream tmpBufStream;
236     bool cond = false;
237     cond = !tmpBufStream.Open(OpenMode::ReadWrite);
238     CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_SOURCE_DATA, "Image temp stream open failed.");
239 
240     cond = !imageStream_->IsOpen();
241     CHECK_ERROR_RETURN_RET_LOG(cond, ERR_IMAGE_SOURCE_DATA, "Output image stream not open.");
242 
243     cond = !UpdateExifMetadata(tmpBufStream, dataBlob, size);
244     CHECK_ERROR_RETURN_RET_LOG(cond, ERROR, "Image temp stream write failed.");
245 
246     imageStream_->Seek(0, SeekPos::BEGIN);
247     cond = !imageStream_->CopyFrom(tmpBufStream);
248     CHECK_ERROR_RETURN_RET_LOG(cond, ERR_MEDIA_INVALID_OPERATION, "Copy from temp stream failed");
249     return SUCCESS;
250 }
251 
UpdateExifMetadata(BufferMetadataStream & bufStream,uint8_t * dataBlob,uint32_t size)252 bool WebpExifMetadataAccessor::UpdateExifMetadata(BufferMetadataStream &bufStream, uint8_t *dataBlob, uint32_t size)
253 {
254     Vp8xAndExifInfo exifFlag = Vp8xAndExifInfo::UNKNOWN;
255     bool cond = false;
256     cond = !WriteHeader(bufStream, size, exifFlag);
257     CHECK_ERROR_RETURN_RET_LOG(cond, false, "Output image stream write header failed.");
258 
259     imageStream_->Seek(WEBP_CHUNK_HEAD_SIZE, SeekPos::BEGIN);
260     cond = !WirteChunkVp8x(bufStream, exifFlag);
261     CHECK_ERROR_RETURN_RET_LOG(cond, false, "Output image stream write vp8x failed.");
262 
263     if (exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST || exifFlag == Vp8xAndExifInfo::EXIF_NOT_EXIST) {
264         return InsertExifMetadata(bufStream, dataBlob, size);
265     }
266 
267     while (!imageStream_->IsEof()) {
268         DataBuf chunkHead(WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE);
269         cond = static_cast<size_t>(imageStream_->Read(chunkHead.Data(), chunkHead.Size())) != chunkHead.Size() ||
270                imageStream_->IsEof();
271         CHECK_ERROR_RETURN_RET_LOG(cond, false, "Failed to read image chunk header information.");
272 
273         uint32_t chunkSize = chunkHead.ReadUInt32(WEBP_CHUNK_ID_SIZE, littleEndian);
274         const ssize_t imgSize = imageStream_->GetSize();
275         cond = chunkSize > imgSize - imageStream_->Tell();
276         CHECK_ERROR_RETURN_RET_LOG(cond, false, "Read chunk length error.");
277 
278         if (chunkSize % WEBP_BUF_SIZE) {
279             ++chunkSize;
280         }
281 
282         DataBuf chunkData(chunkSize);
283         cond = static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size();
284         CHECK_ERROR_RETURN_RET_LOG(cond, false, "Failed to read image chunk data.");
285 
286         std::string strChunkId(reinterpret_cast<const char *>(chunkHead.CData()), WEBP_CHUNK_ID_SIZE);
287         if (strChunkId == WEBP_CHUNK_HEADER_EXIF) {
288             UL2Data(chunkHead.Data(WEBP_FILE_SIZE_BUFF_SIZE), size, littleEndian);
289             bufStream.Write(chunkHead.Data(), chunkHead.Size());
290             bufStream.Write(dataBlob, size);
291             if (chunkData.Size() % WEBP_BUF_SIZE) {
292                 bufStream.Write(&WEBP_PAD_ODD, 1);
293             }
294             break;
295         }
296 
297         bufStream.Write(chunkHead.Data(), chunkHead.Size());
298         bufStream.Write(chunkData.Data(), chunkData.Size());
299     }
300 
301     return CopyRestData(bufStream);
302 }
303 
InsertExifMetadata(BufferMetadataStream & bufStream,uint8_t * dataBlob,uint32_t size)304 bool WebpExifMetadataAccessor::InsertExifMetadata(BufferMetadataStream &bufStream, uint8_t *dataBlob, uint32_t size)
305 {
306     bool cond = !CopyRestData(bufStream);
307     CHECK_ERROR_RETURN_RET(cond, false);
308 
309     static byte exifChunckId[] = { 0x45, 0x58, 0x49, 0x46 };
310     if (bufStream.Write(exifChunckId, WEBP_CHUNK_ID_SIZE) != WEBP_CHUNK_ID_SIZE) {
311         IMAGE_LOGE("BufStream tell: %{public}lu", bufStream.Tell());
312         return false;
313     }
314     DataBuf exifChunckSize(WEBP_CHUNK_SIZE);
315     UL2Data(exifChunckSize.Data(), size, littleEndian);
316     if (bufStream.Write(exifChunckSize.Data(), exifChunckSize.Size()) != (ssize_t)exifChunckSize.Size() ||
317         bufStream.Write(dataBlob, size) != size) {
318         return false;
319     }
320     if (size % WEBP_BUF_SIZE) {
321         bufStream.Write(&WEBP_PAD_ODD, 1);
322     }
323     return true;
324 }
325 
GetImageWidthAndHeight()326 std::tuple<uint32_t, uint32_t> WebpExifMetadataAccessor::GetImageWidthAndHeight()
327 {
328     while (!imageStream_->IsEof()) {
329         DataBuf chunkHead(WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE);
330         if (static_cast<size_t>(imageStream_->Read(chunkHead.Data(), chunkHead.Size())) != chunkHead.Size() ||
331             imageStream_->IsEof()) {
332             IMAGE_LOGE("Failed to read image chunk header information.");
333             return std::make_tuple(0, 0);
334         }
335 
336         const uint32_t size = chunkHead.ReadUInt32(WEBP_CHUNK_ID_SIZE, littleEndian);
337         const ssize_t imgSize = imageStream_->GetSize();
338         if (size > imgSize - imageStream_->Tell()) {
339             IMAGE_LOGE("Read chunk length error.");
340             return std::make_tuple(0, 0);
341         }
342 
343         DataBuf chunkData(size);
344         if (static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size()) {
345             IMAGE_LOGE("Failed to read image chunk data.");
346             return std::make_tuple(0, 0);
347         }
348 
349         std::string strChunkId(reinterpret_cast<const char *>(chunkHead.CData()), WEBP_CHUNK_ID_SIZE);
350         if (strChunkId == WEBP_CHUNK_HEADER_VP8 || strChunkId == WEBP_CHUNK_HEADER_VP8L ||
351             strChunkId == WEBP_CHUNK_HEADER_ANMF) {
352             return GetWidthAndHeightFormChunk(strChunkId, chunkData);
353         }
354     }
355     return std::make_tuple(0, 0);
356 }
357 
GetWidthAndHeightFormChunk(const std::string & strChunkId,const DataBuf & chunkData)358 std::tuple<uint32_t, uint32_t> WebpExifMetadataAccessor::GetWidthAndHeightFormChunk(const std::string &strChunkId,
359     const DataBuf &chunkData)
360 {
361     uint32_t width = 0;
362     uint32_t height = 0;
363     static const uint32_t bitOperVp8 = 0x3fff;
364     static const byte offset3 = 3;
365     static const byte offset2 = 2;
366     if (strChunkId == WEBP_CHUNK_HEADER_VP8 && chunkData.Size() >= (WEBP_CHUNK_HEIGHT_OFFSET + WEBP_BUF_SIZE)) {
367         byte sizeBuf[WEBP_BUF_SIZE];
368 
369         (void)memcpy_s(&sizeBuf, WEBP_BUF_SIZE, chunkData.CData(WEBP_CHUNK_WIDTH_OFFSET), WEBP_BUF_SIZE);
370         width = GetUShort(sizeBuf, littleEndian) & bitOperVp8;
371         (void)memcpy_s(&sizeBuf, WEBP_BUF_SIZE, chunkData.CData(WEBP_CHUNK_HEIGHT_OFFSET), WEBP_BUF_SIZE);
372         height = GetUShort(sizeBuf, littleEndian) & bitOperVp8;
373         return std::make_tuple(width, height);
374     }
375 
376     if (strChunkId == WEBP_CHUNK_HEADER_VP8L && chunkData.Size() >= (WEBP_BUF_SIZE + WEBP_BUF_SIZE + 1)) {
377         byte bufWidth[WEBP_BUF_SIZE];
378         byte bufHeight[WEBP_BUF_SIZE + 1];
379 
380         (void)memcpy_s(&bufWidth, WEBP_BUF_SIZE, chunkData.CData(1), WEBP_BUF_SIZE);
381         bufWidth[1] &= WEBP_VP8L_WIDTH_BIT;
382         width = GetUShort(bufWidth, littleEndian) + 1;
383         (void)memcpy_s(&bufHeight, WEBP_BUF_SIZE + 1, chunkData.CData(WEBP_BUF_SIZE), WEBP_BUF_SIZE + 1);
384         bufHeight[0] = ((bufHeight[0] >> WEBP_CHUNK_WIDTH_OFFSET) & offset3) |
385             ((bufHeight[1] & WEBP_VP8L_HEIGHT_BIT) << offset2);
386         bufHeight[1] = ((bufHeight[1] >> WEBP_CHUNK_WIDTH_OFFSET) & offset3) |
387             ((bufHeight[WEBP_BUF_SIZE] & WEBP_VP8L_HEIGHT_BIT1) << offset2);
388         height = GetUShort(bufHeight, littleEndian) + 1;
389         return std::make_tuple(width, height);
390     }
391 
392     if (strChunkId == WEBP_CHUNK_HEADER_ANMF && chunkData.Size() >= (WEBP_CHUNK_WIDTH_OFFSET + offset3 + offset3)) {
393         byte sizeBuf[WEBP_CHUNK_SIZE];
394 
395         (void)memcpy_s(&sizeBuf, offset3, chunkData.CData(WEBP_CHUNK_WIDTH_OFFSET), offset3);
396         sizeBuf[offset3] = 0;
397         width = GetULong(sizeBuf, littleEndian) + 1;
398         (void)memcpy_s(&sizeBuf, offset3, chunkData.CData(WEBP_CHUNK_WIDTH_OFFSET + offset3), offset3);
399         sizeBuf[offset3] = 0;
400         height = GetULong(sizeBuf, littleEndian) + 1;
401         return std::make_tuple(width, height);
402     }
403     return std::make_tuple(width, height);
404 }
405 
CopyRestData(BufferMetadataStream & bufStream)406 bool WebpExifMetadataAccessor::CopyRestData(BufferMetadataStream &bufStream)
407 {
408     DataBuf buf(WEBP_WRITE_BLOCK);
409     ssize_t readSize = imageStream_->Read(buf.Data(), buf.Size());
410     while (readSize > 0) {
411         if (bufStream.Write(buf.Data(), readSize) != readSize) {
412             IMAGE_LOGE("Write block data to temp stream failed.");
413             return false;
414         }
415         readSize = imageStream_->Read(buf.Data(), buf.Size());
416     }
417 
418     return true;
419 }
420 
WriteHeader(BufferMetadataStream & bufStream,uint32_t size,Vp8xAndExifInfo & exifFlag)421 bool WebpExifMetadataAccessor::WriteHeader(BufferMetadataStream &bufStream, uint32_t size, Vp8xAndExifInfo &exifFlag)
422 {
423     DataBuf headInfo(WEBP_CHUNK_HEAD_SIZE);
424     imageStream_->Seek(0, SeekPos::BEGIN);
425     bool cond = false;
426     cond = static_cast<size_t>(imageStream_->Read(headInfo.Data(), headInfo.Size())) != headInfo.Size() ||
427            imageStream_->IsEof();
428     CHECK_ERROR_RETURN_RET(cond, false);
429     uint32_t fileSize = GetULong(headInfo.Data(WEBP_RIFF_SIZE), littleEndian) + size;
430     if (size % WEBP_BUF_SIZE) {
431         ++fileSize;
432     }
433 
434     cond = !CheckChunkVp8x(exifFlag) && exifFlag == Vp8xAndExifInfo::UNKNOWN;
435     CHECK_ERROR_RETURN_RET(cond, false);
436 
437     if (exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST || exifFlag == Vp8xAndExifInfo::EXIF_NOT_EXIST) {
438         fileSize += exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST ? WEBP_CHUNK_VP8X_SIZE : 0;
439         fileSize += WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE;
440         UL2Data(headInfo.Data(WEBP_FILE_SIZE_BUFF_SIZE), fileSize, littleEndian);
441         IMAGE_LOGD("Write webp file size: %{public}u, new exif size: %{public}u", fileSize, size);
442         return bufStream.Write(headInfo.Data(), headInfo.Size()) == (ssize_t)headInfo.Size();
443     }
444 
445     DataBuf exifData;
446     cond = !ReadBlob(exifData);
447     CHECK_ERROR_RETURN_RET(cond, false);
448 
449     fileSize -= (exifData.Size() % WEBP_BUF_SIZE) ? (exifData.Size() + 1) : exifData.Size();
450     UL2Data(headInfo.Data(WEBP_FILE_SIZE_BUFF_SIZE), fileSize, littleEndian);
451     IMAGE_LOGD("Write webp file size: %{public}u, old exif size: %{public}u, new exif size: %{public}lu",
452         fileSize, size, static_cast<unsigned long>(exifData.Size()));
453     return bufStream.Write(headInfo.Data(), headInfo.Size()) == (ssize_t)headInfo.Size();
454 }
455 
WirteChunkVp8x(BufferMetadataStream & bufStream,const Vp8xAndExifInfo & exifFlag)456 bool WebpExifMetadataAccessor::WirteChunkVp8x(BufferMetadataStream &bufStream, const Vp8xAndExifInfo &exifFlag)
457 {
458     bool cond = false;
459     if (exifFlag == Vp8xAndExifInfo::VP8X_NOT_EXIST) {
460         auto [width, height] = GetImageWidthAndHeight();
461         imageStream_->Seek(WEBP_CHUNK_HEAD_SIZE, SeekPos::BEGIN);
462         cond = width <= 0 || height <= 0;
463         CHECK_ERROR_RETURN_RET(cond, false);
464         static byte chunckHeader[] = { 0x56, 0x50, 0x38, 0x58, 0x0a, 0x00, 0x00, 0x00, 0x08,
465                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
466         size_t offset = WEBP_CHUNK_HEAD_SIZE;
467         uint32_t w = width - 1;
468         chunckHeader[offset] = w & WEBP_CHUNK_OPERATE_FLAG;
469         chunckHeader[++offset] = (w >> WEBP_BYTE_BITS) & WEBP_CHUNK_OPERATE_FLAG;
470         chunckHeader[++offset] = (w >> (WEBP_BYTE_BITS + WEBP_BYTE_BITS)) & WEBP_CHUNK_OPERATE_FLAG;
471 
472         uint32_t h = height - 1;
473         chunckHeader[++offset] = h & WEBP_CHUNK_OPERATE_FLAG;
474         chunckHeader[++offset] = (h >> WEBP_BYTE_BITS) & WEBP_CHUNK_OPERATE_FLAG;
475         chunckHeader[++offset] = (h >> (WEBP_BYTE_BITS + WEBP_BYTE_BITS)) & WEBP_CHUNK_OPERATE_FLAG;
476         return bufStream.Write(chunckHeader, WEBP_CHUNK_VP8X_SIZE) == WEBP_CHUNK_VP8X_SIZE;
477     }
478 
479     DataBuf chunkHead(WEBP_CHUNK_ID_SIZE + WEBP_CHUNK_SIZE);
480     cond = static_cast<size_t>(imageStream_->Read(chunkHead.Data(), chunkHead.Size())) != chunkHead.Size();
481     CHECK_ERROR_RETURN_RET(cond, false);
482     if (bufStream.Write(chunkHead.Data(), chunkHead.Size()) != (ssize_t)chunkHead.Size()) {
483         return false;
484     }
485 
486     const uint32_t size = chunkHead.ReadUInt32(WEBP_CHUNK_ID_SIZE, littleEndian);
487     DataBuf chunkData(size);
488     if (static_cast<size_t>(imageStream_->Read(chunkData.Data(), chunkData.Size())) != chunkData.Size()) {
489         return false;
490     }
491     cond = chunkData.Data() == nullptr;
492     CHECK_ERROR_RETURN_RET(cond, false);
493     chunkData.Data()[0] |= WEBP_EXIF_FLAG_BIT;
494     return bufStream.Write(chunkData.Data(), chunkData.Size()) == (ssize_t)chunkData.Size();
495 }
496 } // namespace Media
497 } // namespace OHOS