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