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