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