| #include "dgif_fuzz_common.h" |
| #include <iostream> |
| |
| using namespace std; |
| |
| extern "C" void PrintGifError(int ErrorCode); |
| |
| int stub_input_reader(GifFileType *gifFileType, GifByteType *gifByteType, int len) |
| { |
| struct gifUserData *gud = (struct gifUserData *)gifFileType->UserData; |
| if (gud->gifLen == 0) |
| return 0; |
| int read_len = (len > gud->gifLen ? gud->gifLen : len); |
| memcpy(gifByteType, gud->gifData, read_len); |
| gud->gifData += read_len; |
| gud->gifLen -= read_len; |
| return read_len; |
| } |
| |
| int fuzz_dgif(const uint8_t *Data, size_t Size) |
| { |
| GifFileType *GifFile; |
| int Error; |
| uint8_t *gifData = (uint8_t *)malloc(Size); |
| memcpy(gifData, Data, Size); |
| struct gifUserData gUData = {Size, gifData}; |
| |
| GifFile = DGifOpen((void *)&gUData, stub_input_reader, &Error); |
| if (GifFile != NULL) |
| { |
| DGifSlurp(GifFile); |
| DGifCloseFile(GifFile, &Error); |
| } |
| free(gifData); |
| return 0; |
| } |
| |
| int fuzz_dgif_extended(const uint8_t *Data, size_t Size) |
| { |
| GifFileType *GifFile; |
| int Error; |
| uint8_t *gifData = (uint8_t *)malloc(Size); |
| memcpy(gifData, Data, Size); |
| struct gifUserData gUData = {Size, gifData}; |
| |
| GifFile = DGifOpen((void *)&gUData, stub_input_reader, &Error); |
| if (GifFile == NULL) |
| { |
| free(gifData); |
| return 0; |
| } |
| if (DGifSlurp(GifFile) != GIF_OK) |
| { |
| DGifCloseFile(GifFile, &Error); |
| free(gifData); |
| return 0; |
| } |
| GraphicsControlBlock gcb; |
| for (int i = 0; i < GifFile->ImageCount; i++) |
| { |
| DGifSavedExtensionToGCB(GifFile, i, &gcb); |
| } |
| const ColorMapObject *cmap = GifFile->SColorMap; |
| if (cmap) |
| { |
| DGifSavedExtensionToGCB(GifFile, 0, &gcb); |
| } |
| DGifCloseFile(GifFile, &Error); |
| free(gifData); |
| return 0; |
| } |
| |
| static Color8888 gifColorToColor8888(const GifColorType &color) |
| { |
| return ARGB_TO_COLOR8888(0xff, color.Red, color.Green, color.Blue); |
| } |
| |
| static bool willBeCleared(const GraphicsControlBlock &gcb) |
| { |
| return gcb.DisposalMode == DISPOSE_BACKGROUND || gcb.DisposalMode == DISPOSE_PREVIOUS; |
| } |
| |
| static long getDelayMs(GraphicsControlBlock &gcb) |
| { |
| return gcb.DelayTime * 10; |
| } |
| |
| int fuzz_dgif_ala_android(const uint8_t *Data, size_t Size) |
| { |
| GifFileType *GifFile; |
| int Error; |
| uint8_t *gifData = (uint8_t *)malloc(Size); |
| memcpy(gifData, Data, Size); |
| struct gifUserData gUData = {Size, gifData}; |
| |
| GifFile = DGifOpen((void *)&gUData, stub_input_reader, &Error); |
| if (GifFile == NULL) |
| { |
| free(gifData); |
| return 0; |
| } |
| |
| if (DGifSlurp(GifFile) != GIF_OK) |
| { |
| PrintGifError(GifFile->Error); |
| DGifCloseFile(GifFile, &Error); |
| free(gifData); |
| return 0; |
| } |
| |
| long durationMs = 0; |
| int lastUnclearedFrame = -1; |
| bool *preservedFrames = new bool[GifFile->ImageCount]; |
| int *restoringFrames = new int[GifFile->ImageCount]; |
| int loopCount = 0; |
| Color8888 bgColor = 0; |
| |
| GraphicsControlBlock gcb; |
| for (int i = 0; i < GifFile->ImageCount; i++) |
| { |
| const SavedImage &image = GifFile->SavedImages[i]; |
| // find the loop extension pair |
| for (int j = 0; (j + 1) < image.ExtensionBlockCount; j++) |
| { |
| ExtensionBlock *eb1 = image.ExtensionBlocks + j; |
| ExtensionBlock *eb2 = image.ExtensionBlocks + j + 1; |
| if (eb1->Function == APPLICATION_EXT_FUNC_CODE |
| // look for "NETSCAPE2.0" app extension |
| && eb1->ByteCount == 11 && !memcmp((const char *)(eb1->Bytes), "NETSCAPE2.0", 11) |
| // verify extension contents and get loop count |
| && eb2->Function == CONTINUE_EXT_FUNC_CODE && eb2->ByteCount == 3 && eb2->Bytes[0] == 1) |
| { |
| loopCount = (int)(eb2->Bytes[2] << 8) + (int)(eb2->Bytes[1]); |
| } |
| } |
| DGifSavedExtensionToGCB(GifFile, i, &gcb); |
| // timing |
| durationMs += getDelayMs(gcb); |
| // preserve logic |
| preservedFrames[i] = false; |
| restoringFrames[i] = -1; |
| if (gcb.DisposalMode == DISPOSE_PREVIOUS && lastUnclearedFrame >= 0) |
| { |
| preservedFrames[lastUnclearedFrame] = true; |
| restoringFrames[i] = lastUnclearedFrame; |
| } |
| if (!willBeCleared(gcb)) |
| { |
| lastUnclearedFrame = i; |
| } |
| // Draw |
| // assert(y+8 <= Image->ImageDesc.Height); |
| // assert(x+8*strlen(legend) <= Image->ImageDesc.Width); |
| int imgHeight = GifFile->SavedImages[i].ImageDesc.Height; |
| int imgWidth = GifFile->SavedImages[i].ImageDesc.Width; |
| // TODO: Source x,y, string, and color from fuzzer input |
| int x = 0; |
| int y = 0; |
| int strLen = 6; |
| if (y + 8 <= imgHeight && x + 8 * strLen <= imgWidth) |
| GifDrawText8x8(&GifFile->SavedImages[i], 0, 0, "legend", 42); |
| } |
| #if GIF_DEBUG |
| ALOGD("FrameSequence_gif created with size %d %d, frames %d dur %ld", |
| GifFile->SWidth, GifFile->SHeight, GifFile->ImageCount, durationMs); |
| for (int i = 0; i < GifFile->ImageCount; i++) |
| { |
| DGifSavedExtensionToGCB(GifFile, i, &gcb); |
| ALOGD(" Frame %d - must preserve %d, restore point %d, trans color %d", |
| i, preservedFrames[i], restoringFrames[i], gcb.TransparentColor); |
| } |
| #endif |
| const ColorMapObject *cmap = GifFile->SColorMap; |
| if (cmap) |
| { |
| // calculate bg color |
| GraphicsControlBlock gcb; |
| DGifSavedExtensionToGCB(GifFile, 0, &gcb); |
| if (gcb.TransparentColor == NO_TRANSPARENT_COLOR && GifFile->SBackGroundColor < cmap->ColorCount) |
| { |
| bgColor = gifColorToColor8888(cmap->Colors[GifFile->SBackGroundColor]); |
| } |
| } |
| |
| DGifCloseFile(GifFile, &Error); |
| free(gifData); |
| delete[] preservedFrames; |
| delete[] restoringFrames; |
| return 0; |
| } |