1 /*
2 * Copyright (C) 2021 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 "gif_decoder.h"
17
18 #include "image_log.h"
19 #include "image_trace.h"
20 #include "image_utils.h"
21 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
22 #include "surface_buffer.h"
23 #endif
24
25 #undef LOG_DOMAIN
26 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
27
28 #undef LOG_TAG
29 #define LOG_TAG "GifDecoder"
30
31 namespace OHOS {
32 namespace ImagePlugin {
33 using namespace MultimediaPlugin;
34 using namespace Media;
35
36 namespace {
37 #if __BYTE_ORDER == __LITTLE_ENDIAN
38 constexpr uint8_t RGBA_R_SHIFT = 0;
39 constexpr uint8_t RGBA_G_SHIFT = 8;
40 constexpr uint8_t RGBA_B_SHIFT = 16;
41 constexpr uint8_t RGBA_A_SHIFT = 24;
42 #else
43 constexpr uint8_t RGBA_R_SHIFT = 24;
44 constexpr uint8_t RGBA_G_SHIFT = 16;
45 constexpr uint8_t RGBA_B_SHIFT = 8;
46 constexpr uint8_t RGBA_A_SHIFT = 0;
47 #endif
48 constexpr uint8_t NO_TRANSPARENT = 0xFF;
49 constexpr uint8_t DELAY_TIME_TO_MS_RATIO = 10;
50 constexpr uint8_t EXTENSION_LEN_INDEX = 0;
51 constexpr uint8_t EXTENSION_DATA_INDEX = 1;
52 constexpr int32_t INTERLACED_PASSES = 4;
53 constexpr int32_t INTERLACED_OFFSET[] = { 0, 4, 2, 1 };
54 constexpr int32_t INTERLACED_INTERVAL[] = { 8, 8, 4, 2 };
55 const std::string IMAGE_DELAY_TIME = "DelayTime";
56 const std::string GIF_IMAGE_LOOP_COUNT = "GIFLoopCount";
57 constexpr int32_t NETSCAPE_EXTENSION_LENGTH = 11;
58 constexpr int32_t DELAY_TIME_LENGTH = 3;
59 constexpr int32_t DELAY_TIME_INDEX1 = 1;
60 constexpr int32_t DELAY_TIME_INDEX2 = 2;
61 constexpr int32_t DELAY_TIME_SHIFT = 8;
62 } // namespace
63
GifDecoder()64 GifDecoder::GifDecoder()
65 {}
66
~GifDecoder()67 GifDecoder::~GifDecoder()
68 {
69 Reset();
70 }
71
SetSource(InputDataStream & sourceStream)72 void GifDecoder::SetSource(InputDataStream &sourceStream)
73 {
74 Reset();
75 inputStreamPtr_ = &sourceStream;
76 }
77
78 // need decode all frame to get total number.
GetTopLevelImageNum(uint32_t & num)79 uint32_t GifDecoder::GetTopLevelImageNum(uint32_t &num)
80 {
81 if (inputStreamPtr_ == nullptr) {
82 IMAGE_LOGE("[GetTopLevelImageNum]set source need firstly");
83 return ERR_IMAGE_DATA_ABNORMAL;
84 }
85 if (!inputStreamPtr_->IsStreamCompleted()) {
86 IMAGE_LOGW("[GetTopLevelImageNum]don't enough data to decode the frame number");
87 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
88 }
89 uint32_t errorCode = CreateGifFileTypeIfNotExist();
90 if (errorCode != SUCCESS) {
91 IMAGE_LOGE("[GetTopLevelImageNum]create GifFileType pointer failed %{public}u", errorCode);
92 return ERR_IMAGE_DECODE_ABNORMAL;
93 }
94 if (!isLoadAllFrame_) {
95 errorCode = UpdateGifFileType(INT_MAX);
96 if (errorCode != SUCCESS) {
97 IMAGE_LOGE("[GetTopLevelImageNum]update GifFileType pointer failed %{public}u", errorCode);
98 return ERR_IMAGE_DECODE_ABNORMAL;
99 }
100 }
101 num = gifPtr_->ImageCount;
102 if (num <= 0) {
103 IMAGE_LOGE("[GetTopLevelImageNum]image frame number must be larger than 0");
104 return ERR_IMAGE_DATA_ABNORMAL;
105 }
106 return SUCCESS;
107 }
108
109 // return background size but not specific frame size, cause of frame drawing on background.
GetImageSize(uint32_t index,Size & size)110 uint32_t GifDecoder::GetImageSize(uint32_t index, Size &size)
111 {
112 uint32_t errorCode = CheckIndex(index);
113 if (errorCode != SUCCESS) {
114 IMAGE_LOGE("[GetImageSize]index %{public}u is invalid %{public}u", index, errorCode);
115 return errorCode;
116 }
117 const int32_t bgWidth = gifPtr_->SWidth;
118 const int32_t bgHeight = gifPtr_->SHeight;
119 if (bgWidth <= 0 || bgHeight <= 0) {
120 IMAGE_LOGE("[GetImageSize]background size [%{public}d, %{public}d] is invalid", bgWidth, bgHeight);
121 return ERR_IMAGE_INVALID_PARAMETER;
122 }
123 size.width = bgWidth;
124 size.height = bgHeight;
125 return SUCCESS;
126 }
127
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)128 uint32_t GifDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
129 {
130 uint32_t errorCode = GetImageSize(index, info.size);
131 if (errorCode != SUCCESS) {
132 IMAGE_LOGE("[SetDecodeOptions]get image size failed %{public}u", errorCode);
133 return errorCode;
134 }
135 info.alphaType = AlphaType::IMAGE_ALPHA_TYPE_OPAQUE;
136 // only support RGBA pixel format for performance.
137 info.pixelFormat = PixelFormat::RGBA_8888;
138 return SUCCESS;
139 }
140
Decode(uint32_t index,DecodeContext & context)141 uint32_t GifDecoder::Decode(uint32_t index, DecodeContext &context)
142 {
143 ImageTrace imageTrace("GifDecoder::Decode, index:%u", index);
144 #if defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
145 context.allocatorType = Media::AllocatorType::HEAP_ALLOC;
146 #endif
147 Size imageSize;
148 uint32_t errorCode = GetImageSize(index, imageSize);
149 if (errorCode != SUCCESS) {
150 IMAGE_LOGE("[Decode]index %{public}u is invalid %{public}u", index, errorCode);
151 return errorCode;
152 }
153 // compute start index and end index.
154 bool isOverlapped = false;
155 uint32_t startIndex = 0;
156 uint32_t endIndex = index;
157 int32_t acquiredIndex = static_cast<int32_t>(index);
158 if (acquiredIndex > lastPixelMapIndex_) {
159 startIndex = lastPixelMapIndex_ + 1;
160 } else if (acquiredIndex == lastPixelMapIndex_) {
161 isOverlapped = true;
162 }
163 // avoid local pixelmap buffer was reset, start with first frame again.
164 if (startIndex != 0 && localPixelMapBuffer_ == nullptr) {
165 startIndex = 0;
166 isOverlapped = false;
167 }
168 IMAGE_LOGD("[Decode]start frame: %{public}u, last frame: %{public}u,"
169 "last pixelMapIndex: %{public}d, isOverlapped: %{public}d",
170 startIndex, endIndex, lastPixelMapIndex_, isOverlapped);
171
172 if (!isOverlapped) {
173 errorCode = OverlapFrame(startIndex, endIndex);
174 if (errorCode != SUCCESS) {
175 IMAGE_LOGE("[Decode]overlap frame failed %{public}u", errorCode);
176 return errorCode;
177 }
178 }
179 errorCode = RedirectOutputBuffer(context);
180 if (errorCode != SUCCESS) {
181 IMAGE_LOGE("[Decode]redirect output stream failed %{public}u", errorCode);
182 return errorCode;
183 }
184 return SUCCESS;
185 }
186
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)187 uint32_t GifDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
188 {
189 uint32_t errorCode = Decode(index, context.decodeContext);
190 // get promote decode progress, in percentage: 0~100.
191 context.totalProcessProgress = (errorCode == SUCCESS ? 100 : 0);
192 return errorCode;
193 }
194
Reset()195 void GifDecoder::Reset()
196 {
197 if (gifPtr_ != nullptr) {
198 DGifCloseFile(gifPtr_, nullptr);
199 gifPtr_ = nullptr;
200 }
201 FreeLocalPixelMapBuffer(); // free local pixelmap buffer
202 inputStreamPtr_ = nullptr;
203 isLoadAllFrame_ = false;
204 lastPixelMapIndex_ = -1;
205 savedFrameIndex_ = -1;
206 bgColor_ = 0;
207 }
208
CreateGifFileTypeIfNotExist()209 uint32_t GifDecoder::CreateGifFileTypeIfNotExist()
210 {
211 if (gifPtr_ == nullptr) {
212 int32_t errorCode = Media::ERROR;
213 if (inputStreamPtr_ == nullptr) {
214 IMAGE_LOGE("[CreateGifFileTypeIfNotExist]set source need firstly");
215 return ERR_IMAGE_GET_DATA_ABNORMAL;
216 }
217 // DGifOpen will create GifFileType pointer and set header and screen desc
218 gifPtr_ = DGifOpen(inputStreamPtr_, InputStreamReader, &errorCode);
219 if (gifPtr_ == nullptr) {
220 IMAGE_LOGE("[CreateGifFileTypeIfNotExist]open image error, %{public}d", errorCode);
221 inputStreamPtr_->Seek(0);
222 savedFrameIndex_ = -1;
223 return ERR_IMAGE_SOURCE_DATA;
224 }
225 ParseBgColor();
226 }
227 return SUCCESS;
228 }
229
InputStreamReader(GifFileType * gif,GifByteType * bytes,int32_t size)230 int32_t GifDecoder::InputStreamReader(GifFileType *gif, GifByteType *bytes, int32_t size)
231 {
232 uint32_t dataSize = 0;
233 if (gif == nullptr) {
234 IMAGE_LOGE("[InputStreamReader]GifFileType pointer is null");
235 return dataSize;
236 }
237 InputDataStream *inputStream = static_cast<InputDataStream *>(gif->UserData);
238 if (inputStream == nullptr) {
239 IMAGE_LOGE("[InputStreamReader]set source need firstly");
240 return dataSize;
241 }
242 if (size <= 0) {
243 IMAGE_LOGE("[InputStreamReader]callback size %{public}d is invalid", size);
244 return dataSize;
245 }
246 if (bytes == nullptr) {
247 IMAGE_LOGE("[InputStreamReader]callback buffer is null");
248 return dataSize;
249 }
250 inputStream->Read(size, bytes, size, dataSize);
251 return dataSize;
252 }
253
CheckIndex(uint32_t index)254 uint32_t GifDecoder::CheckIndex(uint32_t index)
255 {
256 if (!inputStreamPtr_->IsStreamCompleted()) {
257 IMAGE_LOGW("[CheckIndex]don't enough data to decode the frame number");
258 return ERR_IMAGE_SOURCE_DATA_INCOMPLETE;
259 }
260 uint32_t errorCode = CreateGifFileTypeIfNotExist();
261 if (errorCode != SUCCESS) {
262 IMAGE_LOGE("[CheckIndex]create GifFileType failed %{public}u", errorCode);
263 return errorCode;
264 }
265 int32_t updateFrameIndex = static_cast<int32_t>(index);
266 if (!isLoadAllFrame_ && updateFrameIndex > savedFrameIndex_) {
267 errorCode = UpdateGifFileType(updateFrameIndex);
268 if (errorCode != SUCCESS) {
269 IMAGE_LOGE("[CheckIndex]update saved frame to index %{public}u failed", index);
270 return errorCode;
271 }
272 }
273 uint32_t frameNum = gifPtr_->ImageCount;
274 if (index >= frameNum) {
275 IMAGE_LOGE("[CheckIndex]index %{public}u out of frame range %{public}u", index, frameNum);
276 return ERR_IMAGE_INVALID_PARAMETER;
277 }
278 return SUCCESS;
279 }
280
OverlapFrame(uint32_t startIndex,uint32_t endIndex)281 uint32_t GifDecoder::OverlapFrame(uint32_t startIndex, uint32_t endIndex)
282 {
283 for (uint32_t frameIndex = startIndex; frameIndex <= endIndex; frameIndex++) {
284 const SavedImage *savedImage = gifPtr_->SavedImages + frameIndex;
285 if (savedImage == nullptr) {
286 IMAGE_LOGE("[OverlapFrame]image frame %{public}u data is invalid", frameIndex);
287 return ERR_IMAGE_DECODE_ABNORMAL;
288 }
289 // acquire the frame graphices control information
290 int32_t transColor = NO_TRANSPARENT_COLOR;
291 int32_t disposalMode = DISPOSAL_UNSPECIFIED;
292 GetTransparentAndDisposal(frameIndex, transColor, disposalMode);
293 IMAGE_LOGD("[OverlapFrame]frameIndex = %{public}u, transColor = %{public}d, "
294 "disposalMode = %{public}d", frameIndex, transColor, disposalMode);
295
296 if (frameIndex == 0 && AllocateLocalPixelMapBuffer() != SUCCESS) {
297 IMAGE_LOGE("[OverlapFrame]first frame allocate local pixelmap buffer failed");
298 return ERR_IMAGE_DECODE_ABNORMAL;
299 }
300 if (localPixelMapBuffer_ == nullptr) {
301 IMAGE_LOGE("[OverlapFrame]local pixelmap is null, next frame can't overlap");
302 return ERR_IMAGE_DECODE_ABNORMAL;
303 }
304 // current frame recover background
305 if (frameIndex != 0 && disposalMode == DISPOSE_BACKGROUND &&
306 DisposeBackground(frameIndex, savedImage) != SUCCESS) {
307 IMAGE_LOGE("[OverlapFrame]dispose frame %{public}d background failed", frameIndex);
308 return ERR_IMAGE_DECODE_ABNORMAL;
309 }
310 if (disposalMode != DISPOSE_PREVIOUS &&
311 PaddingData(savedImage, transColor) != SUCCESS) {
312 IMAGE_LOGE("[OverlapFrame]dispose frame %{public}u data color failed", frameIndex);
313 return ERR_IMAGE_DECODE_ABNORMAL;
314 }
315 }
316 lastPixelMapIndex_ = endIndex;
317 return SUCCESS;
318 }
319
DisposeBackground(uint32_t frameIndex,const SavedImage * curSavedImage)320 uint32_t GifDecoder::DisposeBackground(uint32_t frameIndex, const SavedImage *curSavedImage)
321 {
322 int32_t preTransColor = NO_TRANSPARENT_COLOR;
323 int32_t preDisposalMode = DISPOSAL_UNSPECIFIED;
324 GetTransparentAndDisposal(frameIndex - 1, preTransColor, preDisposalMode);
325 SavedImage *preSavedImage = gifPtr_->SavedImages + frameIndex - 1;
326 if (preDisposalMode == DISPOSE_BACKGROUND && IsFramePreviousCoveredCurrent(preSavedImage, curSavedImage)) {
327 return SUCCESS;
328 }
329 if (PaddingBgColor(curSavedImage) != SUCCESS) {
330 IMAGE_LOGE("[DisposeBackground]padding frame %{public}u background color failed", frameIndex);
331 return ERR_IMAGE_DECODE_ABNORMAL;
332 }
333 return SUCCESS;
334 }
335
IsFramePreviousCoveredCurrent(const SavedImage * preSavedImage,const SavedImage * curSavedImage)336 bool GifDecoder::IsFramePreviousCoveredCurrent(const SavedImage *preSavedImage, const SavedImage *curSavedImage)
337 {
338 return ((preSavedImage->ImageDesc.Left <= curSavedImage->ImageDesc.Left) &&
339 (preSavedImage->ImageDesc.Left + preSavedImage->ImageDesc.Width >=
340 curSavedImage->ImageDesc.Left + curSavedImage->ImageDesc.Width) &&
341 (preSavedImage->ImageDesc.Top <= curSavedImage->ImageDesc.Top) &&
342 (preSavedImage->ImageDesc.Top + preSavedImage->ImageDesc.Height >=
343 curSavedImage->ImageDesc.Top + curSavedImage->ImageDesc.Height));
344 }
345
AllocateLocalPixelMapBuffer()346 uint32_t GifDecoder::AllocateLocalPixelMapBuffer()
347 {
348 if (localPixelMapBuffer_ == nullptr) {
349 int32_t bgWidth = gifPtr_->SWidth;
350 int32_t bgHeight = gifPtr_->SHeight;
351 if (ImageUtils::CheckMulOverflow(bgWidth, bgHeight, sizeof(uint32_t))) {
352 IMAGE_LOGE("[AllocateLocalPixelMapBuffer]size is invalid, width:%{public}d, height:%{public}d",
353 bgWidth, bgHeight);
354 return ERR_IMAGE_TOO_LARGE;
355 }
356 uint64_t pixelMapBufferSize = static_cast<uint64_t>(bgWidth) *
357 static_cast<uint64_t>(bgHeight) * sizeof(uint32_t);
358 // create local pixelmap buffer, next frame depends on the previous
359 if (pixelMapBufferSize > PIXEL_MAP_MAX_RAM_SIZE) {
360 IMAGE_LOGE("[AllocateLocalPixelMapBuffer]pixelmap buffer size %{public}llu out of max size",
361 static_cast<unsigned long long>(pixelMapBufferSize));
362 return ERR_IMAGE_TOO_LARGE;
363 }
364 localPixelMapBuffer_ = reinterpret_cast<uint32_t *>(malloc(pixelMapBufferSize));
365 if (localPixelMapBuffer_ == nullptr) {
366 IMAGE_LOGE("[AllocateLocalPixelMapBuffer]allocate local pixelmap buffer memory error");
367 return ERR_IMAGE_MALLOC_ABNORMAL;
368 }
369 #ifdef _WIN32
370 errno_t backRet = memset_s(localPixelMapBuffer_, bgColor_, pixelMapBufferSize);
371 if (backRet != EOK) {
372 IMAGE_LOGE("[DisposeFirstPixelMap]memset local pixelmap buffer background failed", backRet);
373 FreeLocalPixelMapBuffer();
374 return ERR_IMAGE_MALLOC_ABNORMAL;
375 }
376 #else
377 if (memset_s(localPixelMapBuffer_, pixelMapBufferSize, bgColor_, pixelMapBufferSize) != EOK) {
378 IMAGE_LOGE("[DisposeFirstPixelMap]memset local pixelmap buffer background failed");
379 FreeLocalPixelMapBuffer();
380 return ERR_IMAGE_MALLOC_ABNORMAL;
381 }
382 #endif
383 }
384 return SUCCESS;
385 }
386
FreeLocalPixelMapBuffer()387 void GifDecoder::FreeLocalPixelMapBuffer()
388 {
389 if (localPixelMapBuffer_ != nullptr) {
390 free(localPixelMapBuffer_);
391 localPixelMapBuffer_ = nullptr;
392 }
393 }
394
PaddingBgColor(const SavedImage * savedImage)395 uint32_t GifDecoder::PaddingBgColor(const SavedImage *savedImage)
396 {
397 int32_t bgWidth = gifPtr_->SWidth;
398 int32_t bgHeight = gifPtr_->SHeight;
399 int32_t frameLeft = savedImage->ImageDesc.Left;
400 int32_t frameTop = savedImage->ImageDesc.Top;
401 int32_t frameWidth = savedImage->ImageDesc.Width;
402 int32_t frameHeight = savedImage->ImageDesc.Height;
403 if (frameLeft + frameWidth > bgWidth) {
404 frameWidth = bgWidth - frameLeft;
405 }
406 if (frameTop + frameHeight > bgHeight) {
407 frameHeight = bgHeight - frameTop;
408 }
409 if (frameWidth < 0 || frameHeight < 0) {
410 IMAGE_LOGE("[PaddingBgColor]frameWidth || frameHeight is abnormal,"
411 "bgWidth:%{public}d, bgHeight:%{public}d, "
412 "frameTop:%{public}d, frameLeft:%{public}d",
413 bgWidth, bgHeight, frameTop, frameLeft);
414 return ERR_IMAGE_DECODE_ABNORMAL;
415 }
416 uint32_t *dstPixelMapBuffer = localPixelMapBuffer_ + frameTop * bgWidth + frameLeft;
417 uint32_t lineBufferSize = frameWidth * sizeof(uint32_t);
418 for (int32_t row = 0; row < frameHeight; row++) {
419 #ifdef _WIN32
420 errno_t backRet = memset_s(dstPixelMapBuffer, bgColor_, lineBufferSize);
421 if (backRet != EOK) {
422 IMAGE_LOGE("[PaddingBgColor]memset local pixelmap buffer failed", backRet);
423 return ERR_IMAGE_MALLOC_ABNORMAL;
424 }
425 #else
426 if (memset_s(dstPixelMapBuffer, lineBufferSize, bgColor_, lineBufferSize) != EOK) {
427 IMAGE_LOGE("[PaddingBgColor]memset local pixelmap buffer failed");
428 return ERR_IMAGE_MALLOC_ABNORMAL;
429 }
430 #endif
431 dstPixelMapBuffer += bgWidth;
432 }
433 return SUCCESS;
434 }
435
PaddingData(const SavedImage * savedImage,int32_t transparentColor)436 uint32_t GifDecoder::PaddingData(const SavedImage *savedImage, int32_t transparentColor)
437 {
438 const ColorMapObject *colorMap = gifPtr_->SColorMap;
439 if (savedImage->ImageDesc.ColorMap != nullptr) {
440 colorMap = savedImage->ImageDesc.ColorMap; // local color map
441 }
442 if (colorMap == nullptr) {
443 IMAGE_LOGE("[PaddingData]color map is null");
444 return ERR_IMAGE_DECODE_ABNORMAL;
445 }
446 int32_t colorCount = colorMap->ColorCount;
447 int32_t bitsPerPixel = colorMap->BitsPerPixel;
448 if ((bitsPerPixel < 0) || (colorCount != (1 << static_cast<uint32_t>(bitsPerPixel)))) {
449 IMAGE_LOGE("[PaddingData]colormap is invalid, bitsPerPixel: %{public}d, colorCount: %{public}d",
450 bitsPerPixel, colorCount);
451 return ERR_IMAGE_DECODE_ABNORMAL;
452 }
453
454 int32_t bgWidth = gifPtr_->SWidth;
455 int32_t bgHeight = gifPtr_->SHeight;
456 int32_t frameLeft = savedImage->ImageDesc.Left;
457 int32_t frameTop = savedImage->ImageDesc.Top;
458 int32_t frameWidth = savedImage->ImageDesc.Width;
459 int32_t frameHeight = savedImage->ImageDesc.Height;
460 if (frameLeft + frameWidth > bgWidth) {
461 frameWidth = bgWidth - frameLeft;
462 }
463 if (frameTop + frameHeight > bgHeight) {
464 frameHeight = bgHeight - frameTop;
465 }
466 const GifByteType *srcFrame = savedImage->RasterBits;
467 uint32_t *dstPixelMapBuffer = localPixelMapBuffer_ + frameTop * bgWidth + frameLeft;
468 for (int32_t row = 0; row < frameHeight; row++) {
469 CopyLine(srcFrame, dstPixelMapBuffer, frameWidth, transparentColor, colorMap);
470 srcFrame += savedImage->ImageDesc.Width;
471 dstPixelMapBuffer += bgWidth;
472 }
473 return SUCCESS;
474 }
475
CopyLine(const GifByteType * srcFrame,uint32_t * dstPixelMapBuffer,int32_t frameWidth,int32_t transparentColor,const ColorMapObject * colorMap)476 void GifDecoder::CopyLine(const GifByteType *srcFrame, uint32_t *dstPixelMapBuffer, int32_t frameWidth,
477 int32_t transparentColor, const ColorMapObject *colorMap)
478 {
479 for (int32_t col = 0; col < frameWidth; col++, srcFrame++, dstPixelMapBuffer++) {
480 if ((*srcFrame != transparentColor) && (*srcFrame < colorMap->ColorCount)) {
481 const GifColorType &colorType = colorMap->Colors[*srcFrame];
482 *dstPixelMapBuffer = GetPixelColor(colorType.Red, colorType.Green, colorType.Blue, NO_TRANSPARENT);
483 }
484 }
485 }
486
GetTransparentAndDisposal(uint32_t index,int32_t & transparentColor,int32_t & disposalMode)487 void GifDecoder::GetTransparentAndDisposal(uint32_t index, int32_t &transparentColor, int32_t &disposalMode)
488 {
489 GraphicsControlBlock graphicsControlBlock = GetGraphicsControlBlock(index);
490 transparentColor = graphicsControlBlock.TransparentColor;
491 disposalMode = graphicsControlBlock.DisposalMode;
492 }
493
GetGraphicsControlBlock(uint32_t index)494 GraphicsControlBlock GifDecoder::GetGraphicsControlBlock(uint32_t index)
495 {
496 GraphicsControlBlock graphicsControlBlock = { DISPOSAL_UNSPECIFIED, false, 0, NO_TRANSPARENT_COLOR };
497 DGifSavedExtensionToGCB(gifPtr_, index, &graphicsControlBlock);
498 return graphicsControlBlock;
499 }
500
GetPixelColor(uint32_t red,uint32_t green,uint32_t blue,uint32_t alpha)501 uint32_t GifDecoder::GetPixelColor(uint32_t red, uint32_t green, uint32_t blue, uint32_t alpha)
502 {
503 return (red << RGBA_R_SHIFT) | (green << RGBA_G_SHIFT) | (blue << RGBA_B_SHIFT) | (alpha << RGBA_A_SHIFT);
504 }
505
ParseBgColor()506 void GifDecoder::ParseBgColor()
507 {
508 const int32_t bgColorIndex = gifPtr_->SBackGroundColor;
509 if (bgColorIndex < 0) {
510 IMAGE_LOGW("[ParseBgColor]bgColor index %{public}d is invalid, use default bgColor", bgColorIndex);
511 return;
512 }
513 const ColorMapObject *bgColorMap = gifPtr_->SColorMap;
514 if ((bgColorMap != nullptr) && (bgColorIndex < bgColorMap->ColorCount)) {
515 const GifColorType bgColorType = bgColorMap->Colors[bgColorIndex];
516 bgColor_ = GetPixelColor(bgColorType.Red, bgColorType.Green, bgColorType.Blue, NO_TRANSPARENT);
517 }
518 }
519
520 constexpr size_t SIZE_ZERO = 0;
521
HeapMemoryCreate(PlImageBuffer & plBuffer)522 static uint32_t HeapMemoryCreate(PlImageBuffer &plBuffer)
523 {
524 IMAGE_LOGD("HeapMemoryCreate IN");
525 if (plBuffer.buffer != nullptr) {
526 IMAGE_LOGD("HeapMemoryCreate has created");
527 return SUCCESS;
528 }
529 if (plBuffer.bufferSize == 0 || plBuffer.bufferSize > PIXEL_MAP_MAX_RAM_SIZE) {
530 IMAGE_LOGE("HeapMemoryCreate Invalid value of bufferSize");
531 return ERR_IMAGE_DATA_ABNORMAL;
532 }
533 auto dataPtr = static_cast<uint8_t *>(malloc(plBuffer.bufferSize));
534 if (dataPtr == nullptr) {
535 IMAGE_LOGE("alloc buffer error");
536 return ERR_IMAGE_MALLOC_ABNORMAL;
537 }
538 plBuffer.buffer = dataPtr;
539 plBuffer.dataSize = plBuffer.bufferSize;
540 return SUCCESS;
541 }
542
HeapMemoryRelease(PlImageBuffer & plBuffer)543 static uint32_t HeapMemoryRelease(PlImageBuffer &plBuffer)
544 {
545 IMAGE_LOGD("HeapMemoryRelease IN");
546 if (plBuffer.buffer == nullptr) {
547 IMAGE_LOGE("HeapMemory::Release nullptr data");
548 return ERR_IMAGE_DATA_ABNORMAL;
549 }
550 free(plBuffer.buffer);
551 plBuffer.buffer = nullptr;
552 return SUCCESS;
553 }
554
DmaMemoryCreate(PlImageBuffer & plBuffer,GifFileType * gifPtr)555 static uint32_t DmaMemoryCreate(PlImageBuffer &plBuffer, GifFileType *gifPtr)
556 {
557 #if defined(_WIN32) || defined(_APPLE) || defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
558 IMAGE_LOGE("Unsupport dma mem alloc");
559 return ERR_IMAGE_DATA_UNSUPPORT;
560 #else
561 sptr<SurfaceBuffer> sb = SurfaceBuffer::Create();
562 BufferRequestConfig requestConfig = {
563 .width = gifPtr->SWidth,
564 .height = gifPtr->SHeight,
565 .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
566 .format = GRAPHIC_PIXEL_FMT_RGBA_8888, // PixelFormat
567 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
568 .timeout = 0,
569 .colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB,
570 .transform = GraphicTransformType::GRAPHIC_ROTATE_NONE,
571 };
572 GSError ret = sb->Alloc(requestConfig);
573 if (ret != GSERROR_OK) {
574 IMAGE_LOGE("SurfaceBuffer Alloc failed, %{public}s", GSErrorStr(ret).c_str());
575 return ERR_DMA_NOT_EXIST;
576 }
577 void* nativeBuffer = sb.GetRefPtr();
578 int32_t err = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
579 if (err != OHOS::GSERROR_OK) {
580 IMAGE_LOGE("NativeBufferReference failed");
581 return ERR_DMA_DATA_ABNORMAL;
582 }
583 plBuffer.buffer = static_cast<uint8_t*>(sb->GetVirAddr());
584 plBuffer.dataSize = plBuffer.bufferSize;
585 plBuffer.context = nativeBuffer;
586 return SUCCESS;
587 #endif
588 }
589
DmaMemoryRelease(PlImageBuffer & plBuffer)590 static uint32_t DmaMemoryRelease(PlImageBuffer &plBuffer)
591 {
592 #if defined(_WIN32) || defined(_APPLE) || defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
593 IMAGE_LOGE("Unsupport dma mem release");
594 return ERR_IMAGE_DATA_UNSUPPORT;
595 #else
596 if (plBuffer.context != nullptr) {
597 int32_t err = ImageUtils::SurfaceBuffer_Unreference(static_cast<SurfaceBuffer*>(plBuffer.context));
598 if (err != OHOS::GSERROR_OK) {
599 IMAGE_LOGE("NativeBufferUnReference failed");
600 return ERR_DMA_DATA_ABNORMAL;
601 }
602 plBuffer.buffer = nullptr;
603 plBuffer.context = nullptr;
604 }
605 return SUCCESS;
606 #endif
607 }
608
609 #if !defined(_WIN32) && !defined(_APPLE) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
ReleaseSharedMemory(int * fdPtr,uint8_t * ptr=nullptr,size_t size=SIZE_ZERO)610 static inline void ReleaseSharedMemory(int* fdPtr, uint8_t* ptr = nullptr, size_t size = SIZE_ZERO)
611 {
612 if (ptr != nullptr && ptr != MAP_FAILED) {
613 ::munmap(ptr, size);
614 }
615 if (fdPtr != nullptr) {
616 ::close(*fdPtr);
617 }
618 }
619
SharedMemoryCreate(PlImageBuffer & plBuffer)620 static uint32_t SharedMemoryCreate(PlImageBuffer &plBuffer)
621 {
622 IMAGE_LOGD("SharedMemoryCreate IN data size %{public}u", plBuffer.bufferSize);
623 if (plBuffer.bufferSize == SIZE_ZERO) {
624 return ERR_IMAGE_DATA_ABNORMAL;
625 }
626 auto fdPtr = std::make_unique<int>();
627 *fdPtr = AshmemCreate("GIF RawData", plBuffer.bufferSize);
628 if (*fdPtr < 0) {
629 IMAGE_LOGE("SharedMemoryCreate AshmemCreate fd:[%{public}d].", *fdPtr);
630 return ERR_IMAGE_DATA_ABNORMAL;
631 }
632 if (AshmemSetProt(*fdPtr, PROT_READ | PROT_WRITE) < 0) {
633 IMAGE_LOGE("SharedMemoryCreate AshmemSetProt errno %{public}d.", errno);
634 ReleaseSharedMemory(fdPtr.get());
635 return ERR_IMAGE_DATA_ABNORMAL;
636 }
637 plBuffer.buffer = ::mmap(nullptr, plBuffer.bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, *fdPtr, 0);
638 if (plBuffer.buffer == MAP_FAILED) {
639 IMAGE_LOGE("SharedMemoryCreate mmap failed, errno:%{public}d", errno);
640 ReleaseSharedMemory(fdPtr.get(), static_cast<uint8_t*>(plBuffer.buffer), plBuffer.bufferSize);
641 return ERR_IMAGE_DATA_ABNORMAL;
642 }
643 plBuffer.context = fdPtr.release();
644 plBuffer.dataSize = plBuffer.bufferSize;
645 return SUCCESS;
646 }
647
SharedMemoryRelease(PlImageBuffer & plBuffer)648 static uint32_t SharedMemoryRelease(PlImageBuffer &plBuffer)
649 {
650 IMAGE_LOGD("SharedMemoryRelease IN");
651 std::unique_ptr<int> fdPtr = std::unique_ptr<int>(static_cast<int*>(plBuffer.context));
652 ReleaseSharedMemory(fdPtr.get(), static_cast<uint8_t*>(plBuffer.buffer), plBuffer.bufferSize);
653 plBuffer.buffer = nullptr;
654 plBuffer.bufferSize = SIZE_ZERO;
655 plBuffer.dataSize = SIZE_ZERO;
656 return SUCCESS;
657 }
658
659 #else
SharedMemoryCreate(PlImageBuffer & plBuffer)660 static uint32_t SharedMemoryCreate(PlImageBuffer &plBuffer)
661 {
662 return ERR_IMAGE_DATA_UNSUPPORT;
663 }
SharedMemoryRelease(PlImageBuffer & plBuffer)664 static uint32_t SharedMemoryRelease(PlImageBuffer &plBuffer)
665 {
666 return ERR_IMAGE_DATA_UNSUPPORT;
667 }
668 #endif
669
AllocMemory(DecodeContext & context,GifFileType * gifPtr)670 static uint32_t AllocMemory(DecodeContext &context, GifFileType *gifPtr)
671 {
672 if (context.pixelsBuffer.buffer != nullptr) {
673 IMAGE_LOGD("AllocMemory has created");
674 return SUCCESS;
675 }
676
677 if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
678 return SharedMemoryCreate(context.pixelsBuffer);
679 } else if (context.allocatorType == Media::AllocatorType::HEAP_ALLOC) {
680 return HeapMemoryCreate(context.pixelsBuffer);
681 } else if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
682 return DmaMemoryCreate(context.pixelsBuffer, gifPtr);
683 }
684 // Current Defalut alloc function
685 return SharedMemoryCreate(context.pixelsBuffer);
686 }
687
FreeMemory(DecodeContext & context)688 static uint32_t FreeMemory(DecodeContext &context)
689 {
690 if (context.pixelsBuffer.buffer == nullptr) {
691 IMAGE_LOGD("FreeMemory has freed");
692 return SUCCESS;
693 }
694
695 if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
696 return SharedMemoryRelease(context.pixelsBuffer);
697 } else if (context.allocatorType == Media::AllocatorType::HEAP_ALLOC) {
698 return HeapMemoryRelease(context.pixelsBuffer);
699 } else if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
700 return DmaMemoryRelease(context.pixelsBuffer);
701 }
702 return ERR_IMAGE_DATA_UNSUPPORT;
703 }
704
RedirectOutputBuffer(DecodeContext & context)705 uint32_t GifDecoder::RedirectOutputBuffer(DecodeContext &context)
706 {
707 if (localPixelMapBuffer_ == nullptr) {
708 IMAGE_LOGE("[RedirectOutputBuffer]local pixelmap buffer is null, redirect failed");
709 return ERR_IMAGE_DECODE_ABNORMAL;
710 }
711 int32_t bgWidth = gifPtr_->SWidth;
712 int32_t bgHeight = gifPtr_->SHeight;
713 if (ImageUtils::CheckMulOverflow(bgWidth, bgHeight, sizeof(uint32_t))) {
714 IMAGE_LOGE("[RedirectOutputBuffer]size is invalid, width:%{public}d, height:%{public}d",
715 bgWidth, bgHeight);
716 return ERR_IMAGE_TOO_LARGE;
717 }
718 uint64_t imageBufferSize = static_cast<uint64_t>(bgWidth) *
719 static_cast<uint64_t>(bgHeight) * sizeof(uint32_t);
720 uint32_t allocRes = SUCCESS;
721 if (context.pixelsBuffer.buffer == nullptr) {
722 context.pixelsBuffer.bufferSize = imageBufferSize;
723 allocRes = AllocMemory(context, gifPtr_);
724 if (context.pixelsBuffer.buffer == nullptr) {
725 return (allocRes != SUCCESS) ? allocRes : ERR_IMAGE_DATA_ABNORMAL;
726 }
727 }
728 if (memcpy_s(context.pixelsBuffer.buffer, context.pixelsBuffer.bufferSize,
729 localPixelMapBuffer_, imageBufferSize) != 0) {
730 IMAGE_LOGE("[RedirectOutputBuffer]memory copy size %{public}llu failed",
731 static_cast<unsigned long long>(imageBufferSize));
732 FreeMemory(context);
733 return ERR_IMAGE_DECODE_ABNORMAL;
734 }
735 return SUCCESS;
736 }
737
GetImageDelayTime(uint32_t index,int32_t & value)738 uint32_t GifDecoder::GetImageDelayTime(uint32_t index, int32_t &value)
739 {
740 uint32_t errorCode = CheckIndex(index);
741 if (errorCode != SUCCESS) {
742 IMAGE_LOGE("[GetImageDelayTime]index %{public}u is invalid", index);
743 return errorCode;
744 }
745
746 GraphicsControlBlock graphicsControlBlock = GetGraphicsControlBlock(index);
747 // 0.01 sec in standard, update to ms
748 value = graphicsControlBlock.DelayTime * DELAY_TIME_TO_MS_RATIO;
749 return SUCCESS;
750 }
751
GetImageLoopCount(uint32_t index,int32_t & value)752 uint32_t GifDecoder::GetImageLoopCount(uint32_t index, int32_t &value)
753 {
754 for (int i = 0; i < gifPtr_->SavedImages[index].ExtensionBlockCount; i++) {
755 ExtensionBlock *ep = &gifPtr_->SavedImages[index].ExtensionBlocks[i];
756 if (ep == nullptr) {
757 continue;
758 }
759 if ((ep->Function == APPLICATION_EXT_FUNC_CODE) && (ep->ByteCount >= NETSCAPE_EXTENSION_LENGTH) &&
760 (memcmp(ep->Bytes, "NETSCAPE2.0", NETSCAPE_EXTENSION_LENGTH) == 0)) {
761 ep++;
762 if (ep->ByteCount >= DELAY_TIME_LENGTH) {
763 unsigned char *params = ep->Bytes;
764 value = params[DELAY_TIME_INDEX1] | (params[DELAY_TIME_INDEX2] << DELAY_TIME_SHIFT);
765 return SUCCESS;
766 }
767 }
768 }
769 return ERR_IMAGE_PROPERTY_NOT_EXIST;
770 }
771
GetImagePropertyInt(uint32_t index,const std::string & key,int32_t & value)772 uint32_t GifDecoder::GetImagePropertyInt(uint32_t index, const std::string &key, int32_t &value)
773 {
774 IMAGE_LOGD("[GetImagePropertyInt] enter gif plugin, key:%{public}s", key.c_str());
775 uint32_t errorCode = CheckIndex(0);
776 if (errorCode != SUCCESS) {
777 IMAGE_LOGE("[GetImagePropertyInt]index %{public}u is invalid", index);
778 return errorCode;
779 }
780
781 if (key == IMAGE_DELAY_TIME) {
782 errorCode = GetImageDelayTime(index, value);
783 } else if (key == GIF_IMAGE_LOOP_COUNT) {
784 errorCode = GetImageLoopCount(0, value);
785 } else {
786 IMAGE_LOGE("[GetImagePropertyInt]key(%{public}s) not supported", key.c_str());
787 return ERR_IMAGE_INVALID_PARAMETER;
788 }
789
790 return errorCode;
791 }
792
GetImagePropertyString(uint32_t index,const std::string & key,std::string & value)793 uint32_t GifDecoder::GetImagePropertyString(uint32_t index, const std::string &key, std::string &value)
794 {
795 IMAGE_LOGD("[GetImagePropertyString] enter, index:%{public}u, key:%{public}s", index, key.c_str());
796
797 if (key != IMAGE_DELAY_TIME) {
798 return AbsImageDecoder::GetImagePropertyString(index, key, value);
799 }
800
801 int32_t intValue = 0;
802 uint32_t errorCode = GetImagePropertyInt(index, key, intValue);
803 if (errorCode != SUCCESS) {
804 IMAGE_LOGE("[GetImagePropertyString] errorCode:%{public}u,"
805 " index:%{public}u, key:%{public}s", errorCode, index, key.c_str());
806 return errorCode;
807 }
808
809 value = std::to_string(intValue);
810
811 IMAGE_LOGD("[GetImagePropertyString] leave, index:%{public}u, key:%{public}s, value:%{public}s",
812 index, key.c_str(), value.c_str());
813 return SUCCESS;
814 }
815
ParseFrameDetail()816 uint32_t GifDecoder::ParseFrameDetail()
817 {
818 if (DGifGetImageDesc(gifPtr_) == GIF_ERROR) {
819 IMAGE_LOGE("[ParseFrameDetail]parse frame desc to gif pointer failed %{public}d", gifPtr_->Error);
820 return ERR_IMAGE_DECODE_ABNORMAL;
821 }
822 // DGifGetImageDesc use malloc or reallocarray allocate savedImages memory and increase imageCount.
823 // If error, we don't free the memory, next time decode will retry the allocated memory.
824 // The total memory free will be called DGifCloseFile.
825 int32_t frameIndex = gifPtr_->ImageCount - 1;
826 SavedImage *saveImagePtr = &gifPtr_->SavedImages[frameIndex];
827 int32_t imageWidth = saveImagePtr->ImageDesc.Width;
828 int32_t imageHeight = saveImagePtr->ImageDesc.Height;
829 if (ImageUtils::CheckMulOverflow(imageWidth, imageHeight)) {
830 IMAGE_LOGE("[ParseFrameDetail]size is invalid, size: [%{public}d, %{public}d]", imageWidth,
831 imageHeight);
832 // if error, imageCount go back and next time DGifGetImageDesc will retry.
833 gifPtr_->ImageCount--;
834 return ERR_IMAGE_DECODE_ABNORMAL;
835 }
836 uint64_t imageSize = static_cast<uint64_t>(imageWidth) * static_cast<uint64_t>(imageHeight);
837 if (imageWidth <= 0 || imageHeight <= 0 || imageSize > SIZE_MAX) {
838 IMAGE_LOGE("[ParseFrameDetail]check frame size[%{public}d, %{public}d] failed", imageWidth,
839 imageHeight);
840 // if error, imageCount go back and next time DGifGetImageDesc will retry.
841 gifPtr_->ImageCount--;
842 return ERR_IMAGE_DECODE_ABNORMAL;
843 }
844 // set savedImage extension
845 if (gifPtr_->ExtensionBlocks != nullptr) {
846 saveImagePtr->ExtensionBlocks = gifPtr_->ExtensionBlocks;
847 saveImagePtr->ExtensionBlockCount = gifPtr_->ExtensionBlockCount;
848 gifPtr_->ExtensionBlocks = nullptr;
849 gifPtr_->ExtensionBlockCount = 0;
850 }
851 // set savedImage rasterBits
852 if (SetSavedImageRasterBits(saveImagePtr, frameIndex, imageSize, imageWidth, imageHeight) != SUCCESS) {
853 IMAGE_LOGE("[ParseFrameDetail] set saved image data failed");
854 GifFreeExtensions(&saveImagePtr->ExtensionBlockCount, &saveImagePtr->ExtensionBlocks);
855 return ERR_IMAGE_DECODE_ABNORMAL;
856 }
857 return SUCCESS;
858 }
859
SetSavedImageRasterBits(SavedImage * saveImagePtr,int32_t frameIndex,uint64_t imageSize,int32_t imageWidth,int32_t imageHeight)860 uint32_t GifDecoder::SetSavedImageRasterBits(SavedImage *saveImagePtr, int32_t frameIndex, uint64_t imageSize,
861 int32_t imageWidth, int32_t imageHeight)
862 {
863 if (saveImagePtr->RasterBits == nullptr) {
864 if (imageSize == 0 || imageSize > PIXEL_MAP_MAX_RAM_SIZE) {
865 IMAGE_LOGE("[SetSavedImageData]malloc frame %{public}d failed for invalid imagesize", frameIndex);
866 return ERR_IMAGE_MALLOC_ABNORMAL;
867 }
868 saveImagePtr->RasterBits = static_cast<GifPixelType *>(malloc(imageSize * sizeof(GifPixelType)));
869 if (saveImagePtr->RasterBits == nullptr) {
870 IMAGE_LOGE("[SetSavedImageData]malloc frame %{public}d rasterBits failed", frameIndex);
871 return ERR_IMAGE_MALLOC_ABNORMAL;
872 }
873 }
874 // if error next time will retry the rasterBits and the pointer free will be called DGifCloseFile.
875 if (saveImagePtr->ImageDesc.Interlace) {
876 for (int32_t i = 0; i < INTERLACED_PASSES; i++) {
877 for (int32_t j = INTERLACED_OFFSET[i]; j < imageHeight; j += INTERLACED_INTERVAL[i]) {
878 if (DGifGetLine(gifPtr_, saveImagePtr->RasterBits + j * imageWidth, imageWidth) == GIF_ERROR) {
879 IMAGE_LOGE("[SetSavedImageData]interlace set frame %{public}d bits failed %{public}d",
880 frameIndex, gifPtr_->Error);
881 return ERR_IMAGE_DECODE_ABNORMAL;
882 }
883 }
884 }
885 } else {
886 if (DGifGetLine(gifPtr_, saveImagePtr->RasterBits, imageSize) == GIF_ERROR) {
887 IMAGE_LOGE("[SetSavedImageData]normal set frame %{public}d bits failed %{public}d", frameIndex,
888 gifPtr_->Error);
889 return ERR_IMAGE_DECODE_ABNORMAL;
890 }
891 }
892 return SUCCESS;
893 }
894
ParseFrameExtension()895 uint32_t GifDecoder::ParseFrameExtension()
896 {
897 GifByteType *extData = nullptr;
898 int32_t extFunc = 0;
899 if (DGifGetExtension(gifPtr_, &extFunc, &extData) == GIF_ERROR) {
900 IMAGE_LOGE("[ParseFrameExtension]get extension failed %{public}d", gifPtr_->Error);
901 return ERR_IMAGE_DECODE_ABNORMAL;
902 }
903 if (extData == nullptr) {
904 return SUCCESS;
905 }
906
907 IMAGE_LOGD("[ParseFrameExtension] get extension:0x%{public}x", extFunc);
908
909 if (GifAddExtensionBlock(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks, extFunc,
910 extData[EXTENSION_LEN_INDEX], &extData[EXTENSION_DATA_INDEX]) == GIF_ERROR) {
911 IMAGE_LOGE("[ParseFrameExtension]set extension to gif pointer failed");
912 // GifAddExtensionBlock will allocate memory, if error, free extension ready to retry
913 GifFreeExtensions(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks);
914 return ERR_IMAGE_DECODE_ABNORMAL;
915 }
916 while (true) {
917 if (DGifGetExtensionNext(gifPtr_, &extData) == GIF_ERROR) {
918 IMAGE_LOGE("[ParseFrameExtension]get next extension failed %{public}d", gifPtr_->Error);
919 return ERR_IMAGE_DECODE_ABNORMAL;
920 }
921 if (extData == nullptr) {
922 return SUCCESS;
923 }
924
925 if (GifAddExtensionBlock(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks, CONTINUE_EXT_FUNC_CODE,
926 extData[EXTENSION_LEN_INDEX], &extData[EXTENSION_DATA_INDEX]) == GIF_ERROR) {
927 IMAGE_LOGE("[ParseFrameExtension]set next extension to gif pointer failed");
928 GifFreeExtensions(&gifPtr_->ExtensionBlockCount, &gifPtr_->ExtensionBlocks);
929 return ERR_IMAGE_DECODE_ABNORMAL;
930 }
931 }
932 return SUCCESS;
933 }
934
UpdateGifFileType(int32_t updateFrameIndex)935 uint32_t GifDecoder::UpdateGifFileType(int32_t updateFrameIndex)
936 {
937 IMAGE_LOGD("[UpdateGifFileType]update %{public}d to %{public}d", savedFrameIndex_, updateFrameIndex);
938 uint32_t startPosition = inputStreamPtr_->Tell();
939 GifRecordType recordType;
940 gifPtr_->ExtensionBlocks = nullptr;
941 gifPtr_->ExtensionBlockCount = 0;
942 do {
943 if (DGifGetRecordType(gifPtr_, &recordType) == GIF_ERROR) {
944 IMAGE_LOGE("[UpdateGifFileType]parse file record type failed %{public}d", gifPtr_->Error);
945 inputStreamPtr_->Seek(startPosition);
946 return ERR_IMAGE_DECODE_ABNORMAL;
947 }
948
949 switch (recordType) {
950 case EXTENSION_RECORD_TYPE:
951 if (ParseFrameExtension() != SUCCESS) {
952 IMAGE_LOGE("[UpdateGifFileType]parse frame extension failed");
953 inputStreamPtr_->Seek(startPosition);
954 return ERR_IMAGE_DECODE_ABNORMAL;
955 }
956 break;
957 case IMAGE_DESC_RECORD_TYPE:
958 if (ParseFrameDetail() != SUCCESS) {
959 IMAGE_LOGE("[UpdateGifFileType]parse frame detail failed");
960 inputStreamPtr_->Seek(startPosition);
961 return ERR_IMAGE_DECODE_ABNORMAL;
962 }
963 savedFrameIndex_ = gifPtr_->ImageCount - 1;
964 startPosition = inputStreamPtr_->Tell();
965 break;
966 case TERMINATE_RECORD_TYPE:
967 IMAGE_LOGD("[UpdateGifFileType]parse gif completed");
968 isLoadAllFrame_ = true;
969 break;
970 default:
971 break;
972 }
973
974 if (isLoadAllFrame_ || savedFrameIndex_ == updateFrameIndex) {
975 break;
976 }
977 } while (recordType != TERMINATE_RECORD_TYPE);
978
979 if (gifPtr_->ImageCount <= 0) {
980 gifPtr_->Error = D_GIF_ERR_NO_IMAG_DSCR;
981 IMAGE_LOGE("[UpdateGifFileType]has no frame in gif block");
982 return ERR_IMAGE_DECODE_ABNORMAL;
983 }
984 return SUCCESS;
985 }
986 } // namespace ImagePlugin
987 } // namespace OHOS