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