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