Bump to 5.2.1
[platform/upstream/giflib.git] / giftext.c
1 /*****************************************************************************
2
3 giftext - dump GIF pixels and metadata as text
4
5 SPDX-License-Identifier: MIT
6
7 *****************************************************************************/
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <ctype.h>
12 #include <fcntl.h>
13 #include <stdbool.h>
14
15 #ifdef _WIN32
16 #include <io.h>
17 #endif /* _WIN32 */
18
19 #include "gif_lib.h"
20 #include "getarg.h"
21
22 #define PROGRAM_NAME    "giftext"
23
24 #define MAKE_PRINTABLE(c)  (isprint(c) ? (c) : ' ')
25
26 __attribute__((__section__(".tizen.build-id")))
27 static char
28     VersionStr[] =
29         PROGRAM_NAME
30         VERSION_COOKIE
31         "       Gershon Elber,  "
32         __DATE__ ",   " __TIME__ "\n"
33         "(C) Copyright 1989 Gershon Elber.\n";
34 static char
35     *CtrlStr =
36         PROGRAM_NAME
37         " v%- c%- e%- z%- p%- r%- h%- GifFile!*s";
38
39 static void PrintCodeBlock(GifFileType *GifFile, GifByteType *CodeBlock, bool Reset);
40 static void PrintPixelBlock(GifByteType *PixelBlock, int Len, bool Reset);
41 static void PrintExtBlock(GifByteType *Extension, bool Reset);
42 static void PrintLZCodes(GifFileType *GifFile);
43
44 /******************************************************************************
45  Interpret the command line and scan the given GIF file.
46 ******************************************************************************/
47 int main(int argc, char **argv)
48 {
49     int i, j, ExtCode, ErrorCode, CodeSize, NumFiles, Len, ImageNum = 1;
50     bool Error,
51         ColorMapFlag = false, EncodedFlag = false, LZCodesFlag = false,
52         PixelFlag = false, HelpFlag = false, RawFlag = false; 
53     char *GifFileName, **FileName = NULL;
54     GifPixelType *Line;
55     GifRecordType RecordType;
56     GifByteType *CodeBlock, *Extension;
57     GifFileType *GifFile;
58
59     if ((Error = GAGetArgs(argc, argv, CtrlStr,
60                 &GifNoisyPrint, &ColorMapFlag, &EncodedFlag,
61                 &LZCodesFlag, &PixelFlag, &RawFlag, &HelpFlag,
62                 &NumFiles, &FileName)) != false ||
63         (NumFiles > 1 && !HelpFlag)) {
64         if (Error)
65             GAPrintErrMsg(Error);
66         else if (NumFiles > 1)
67             GIF_MESSAGE("Error in command line parsing - one GIF file please.");
68         GAPrintHowTo(CtrlStr);
69         exit(EXIT_FAILURE);
70     }
71
72     if (HelpFlag) {
73         (void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
74         GAPrintHowTo(CtrlStr);
75         exit(EXIT_SUCCESS);
76     }
77
78     if (NumFiles == 1) {
79         GifFileName = *FileName;
80         if ((GifFile = DGifOpenFileName(*FileName, &ErrorCode)) == NULL) {
81             PrintGifError(ErrorCode);
82             exit(EXIT_FAILURE);
83         }
84     }
85     else {
86         /* Use stdin instead: */
87         GifFileName = "Stdin";
88         if ((GifFile = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
89             PrintGifError(ErrorCode);
90             exit(EXIT_FAILURE);
91         }
92     }
93
94     /* Because we write binary data - make sure no text will be written. */
95     if (RawFlag) {
96         ColorMapFlag = EncodedFlag = LZCodesFlag = PixelFlag = false;
97 #ifdef _WIN32
98         _setmode(1, O_BINARY);             /* Make sure it is in binary mode. */
99 #endif /* _WIN32 */
100     }
101     else {
102         printf("\n%s:\n\n\tScreen Size - Width = %d, Height = %d.\n",
103                GifFileName, GifFile->SWidth, GifFile->SHeight);
104         printf("\tColorResolution = %d, BitsPerPixel = %d, BackGround = %d, Aspect = %d.\n",
105                GifFile->SColorResolution,
106                GifFile->SColorMap ? GifFile->SColorMap->BitsPerPixel : 0,
107                GifFile->SBackGroundColor,
108                GifFile->AspectByte);
109         if (GifFile->SColorMap)
110             printf("\tHas Global Color Map.\n\n");
111         else
112             printf("\tNo Global Color Map.\n\n");
113         if (ColorMapFlag && GifFile->SColorMap) {
114             printf("\tGlobal Color Map:\n");
115             Len = GifFile->SColorMap->ColorCount;
116             printf("\tSort Flag: %s\n", 
117                    GifFile->SColorMap->SortFlag ? "on":"off");
118             for (i = 0; i < Len; i+=4) {
119                 for (j = 0; j < 4 && j < Len; j++) {
120                     printf("%3d: %02xh %02xh %02xh   ", i + j,
121                            GifFile->SColorMap->Colors[i + j].Red,
122                            GifFile->SColorMap->Colors[i + j].Green,
123                            GifFile->SColorMap->Colors[i + j].Blue);
124                 }
125                 printf("\n");
126             }
127         }
128     }
129
130     do {
131         if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
132             PrintGifError(GifFile->Error);
133             exit(EXIT_FAILURE);
134         }
135         switch (RecordType) {
136             case IMAGE_DESC_RECORD_TYPE:
137                 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
138                     PrintGifError(GifFile->Error);
139                     exit(EXIT_FAILURE);
140                 }
141                 if (!RawFlag) {
142                     printf("\nImage #%d:\n\n\tImage Size - Left = %d, Top = %d, Width = %d, Height = %d.\n",
143                            ImageNum++, GifFile->Image.Left, GifFile->Image.Top,
144                            GifFile->Image.Width, GifFile->Image.Height);
145                     printf("\tImage is %s",
146                            GifFile->Image.Interlace ? "Interlaced" :
147                                                     "Non Interlaced");
148                     if (GifFile->Image.ColorMap != NULL)
149                         printf(", BitsPerPixel = %d.\n",
150                                 GifFile->Image.ColorMap->BitsPerPixel);
151                     else
152                         printf(".\n");
153                     if (GifFile->Image.ColorMap)
154                         printf("\tImage Has Color Map.\n");
155                     else
156                         printf("\tNo Image Color Map.\n");
157                     if (ColorMapFlag && GifFile->Image.ColorMap) {
158                         printf("\tSort Flag: %s\n", 
159                                GifFile->Image.ColorMap->SortFlag ? "on":"off");
160                         Len = 1 << GifFile->Image.ColorMap->BitsPerPixel;
161                         for (i = 0; i < Len; i+=4) {
162                             for (j = 0; j < 4 && j < Len; j++) {
163                                 printf("%3d: %02xh %02xh %02xh   ", i + j,
164                                        GifFile->Image.ColorMap->Colors[i + j].Red,
165                                        GifFile->Image.ColorMap->Colors[i + j].Green,
166                                        GifFile->Image.ColorMap->Colors[i + j].Blue);
167                             }
168                             printf("\n");
169                         }
170                     }
171                 }
172
173                 if (EncodedFlag) {
174                     if (DGifGetCode(GifFile, &CodeSize, &CodeBlock) == GIF_ERROR) {
175                         PrintGifError(GifFile->Error);
176                         exit(EXIT_FAILURE);
177                     }
178                     printf("\nImage LZ compressed Codes (Code Size = %d):\n",
179                            CodeSize);
180                     PrintCodeBlock(GifFile, CodeBlock, true);
181                     while (CodeBlock != NULL) {
182                         if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
183                             PrintGifError(GifFile->Error);
184                             exit(EXIT_FAILURE);
185                         }
186                         PrintCodeBlock(GifFile, CodeBlock, false);
187                     }
188                 }
189                 else if (LZCodesFlag) {
190                     PrintLZCodes(GifFile);
191                 }
192                 else if (PixelFlag) {
193                     Line = (GifPixelType *) malloc(GifFile->Image.Width *
194                                                 sizeof(GifPixelType));
195                     for (i = 0; i < GifFile->Image.Height; i++) {
196                         if (DGifGetLine(GifFile, Line, GifFile->Image.Width)
197                             == GIF_ERROR) {
198                             PrintGifError(GifFile->Error);
199                             exit(EXIT_FAILURE);
200                         }
201                         PrintPixelBlock(Line, GifFile->Image.Width, i == 0);
202                     }
203                     PrintPixelBlock(NULL, GifFile->Image.Width, false);
204                     free((char *) Line);
205                 }
206                 else if (RawFlag) {
207                     Line = (GifPixelType *) malloc(GifFile->Image.Width *
208                                                 sizeof(GifPixelType));
209                     for (i = 0; i < GifFile->Image.Height; i++) {
210                         if (DGifGetLine(GifFile, Line, GifFile->Image.Width)
211                             == GIF_ERROR) {
212                             PrintGifError(GifFile->Error);
213                             exit(EXIT_FAILURE);
214                         }
215                         fwrite(Line, 1, GifFile->Image.Width, stdout);
216                     }
217                     free((char *) Line);
218                 }
219                 else {
220                     /* Skip the image: */
221                     if (DGifGetCode(GifFile, &CodeSize, &CodeBlock) == GIF_ERROR) {
222                         PrintGifError(GifFile->Error);
223                         exit(EXIT_FAILURE);
224                     }
225                     while (CodeBlock != NULL) {
226                         if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
227                             PrintGifError(GifFile->Error);
228                             exit(EXIT_FAILURE);
229                         }
230                     }
231
232                 }
233                 break;
234             case EXTENSION_RECORD_TYPE:
235                 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
236                     PrintGifError(GifFile->Error);
237                     exit(EXIT_FAILURE);
238                 }
239                 if (!RawFlag) {
240                     putchar('\n');
241                     switch (ExtCode)
242                     {
243                     case COMMENT_EXT_FUNC_CODE:
244                         printf("GIF89 comment");
245                         break;
246                     case GRAPHICS_EXT_FUNC_CODE:
247                         printf("GIF89 graphics control");
248                         break;
249                     case PLAINTEXT_EXT_FUNC_CODE:
250                         printf("GIF89 plaintext");
251                         break;
252                     case APPLICATION_EXT_FUNC_CODE:
253                         printf("GIF89 application block");
254                         break;
255                     default:
256                         printf("Extension record of unknown type");
257                         break;
258                     }
259                     printf(" (Ext Code = %d [%c]):\n",
260                            ExtCode, MAKE_PRINTABLE(ExtCode));
261                     PrintExtBlock(Extension, true);
262
263                     if (ExtCode == GRAPHICS_EXT_FUNC_CODE) {
264                         GraphicsControlBlock gcb;
265                         if (Extension == NULL) {
266                             printf("Invalid extension block\n");
267                             GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
268                             PrintGifError(GifFile->Error);
269                             exit(EXIT_FAILURE);
270                         }
271                         if (DGifExtensionToGCB(Extension[0], Extension+1, &gcb) == GIF_ERROR) {
272                             PrintGifError(GifFile->Error);
273                             exit(EXIT_FAILURE);
274                         }
275                         printf("\tDisposal Mode: %d\n", gcb.DisposalMode);
276                         printf("\tUser Input Flag: %d\n", gcb.UserInputFlag);
277                         printf("\tTransparency on: %s\n",
278                                gcb.TransparentColor != -1 ? "yes" : "no");
279                         printf("\tDelayTime: %d\n", gcb.DelayTime);
280                         printf("\tTransparent Index: %d\n", gcb.TransparentColor);
281                     }
282                 }
283                 for (;;) {
284                     if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
285                         PrintGifError(GifFile->Error);
286                         exit(EXIT_FAILURE);
287                     }
288                     if (Extension == NULL)
289                         break;
290                     PrintExtBlock(Extension, false);
291                 }
292                 break;
293             case TERMINATE_RECORD_TYPE:
294                 break;
295             default:         /* Should be trapped by DGifGetRecordType */
296                 break;
297         }
298     }
299     while (RecordType != TERMINATE_RECORD_TYPE);
300
301     if (DGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR) {
302         PrintGifError(ErrorCode);
303         exit(EXIT_FAILURE);
304     }
305
306     if (!RawFlag) printf("\nGIF file terminated normally.\n");
307
308     return 0;
309 }
310
311 /******************************************************************************
312  Print the given CodeBlock - a string in pascal notation (size in first
313  place). Save local information so printing can be performed continuously,
314  or reset to start state if Reset. If CodeBlock is NULL, output is flushed
315 ******************************************************************************/
316 static void PrintCodeBlock(GifFileType *GifFile, GifByteType *CodeBlock, bool Reset)
317 {
318     static int CrntPlace = 0; 
319     static long CodeCount = 0;
320     int i, Len;
321
322     if (Reset || CodeBlock == NULL) {
323         if (CodeBlock == NULL) {
324             long NumBytes = 0;
325             if (CrntPlace > 0) {
326                 printf("\n");
327                 CodeCount += CrntPlace - 16;
328             }
329             if (GifFile->Image.ColorMap)
330                 NumBytes = ((((long) GifFile->Image.Width) * GifFile->Image.Height)
331                                 * GifFile->Image.ColorMap->BitsPerPixel) / 8;
332             else if (GifFile->SColorMap != NULL)
333                 NumBytes = ((((long) GifFile->Image.Width) * GifFile->Image.Height)
334                                 * GifFile->SColorMap->BitsPerPixel) / 8;
335             /* FIXME: What should the compression ratio be if no color table? */
336             if (NumBytes > 0) {
337                 int Percent = 100 * CodeCount / NumBytes;
338                 printf("\nCompression ratio: %ld/%ld (%d%%).\n",
339                         CodeCount, NumBytes, Percent);
340             }
341             return;
342         }
343         CrntPlace = 0;
344         CodeCount = 0;
345     }
346
347     Len = CodeBlock[0];
348     for (i = 1; i <= Len; i++) {
349         if (CrntPlace == 0) {
350             printf("\n%05lxh:  ", CodeCount);
351             CodeCount += 16;
352         }
353         (void)printf(" %02xh", CodeBlock[i]);
354         if (++CrntPlace >= 16) CrntPlace = 0;
355     }
356 }
357
358 /******************************************************************************
359  Print the given Extension - a string in pascal notation (size in first
360  place). Save local information so printing can be performed continuously,
361  or reset to start state if Reset. If Extension is NULL, output is flushed
362 ******************************************************************************/
363 static void PrintExtBlock(GifByteType *Extension, bool Reset)
364 {
365     static int CrntPlace = 0;
366     static long ExtCount = 0;
367     static char HexForm[49], AsciiForm[17];
368
369     if (Reset || Extension == NULL) {
370         if (Extension == NULL) {
371             if (CrntPlace > 0) {
372                 HexForm[CrntPlace * 3] = 0;
373                 AsciiForm[CrntPlace] = 0;
374                 printf("\n%05lx: %-49s  %-17s\n", ExtCount, HexForm, AsciiForm);
375                 return;
376             }
377             else
378                 printf("\n");
379         }
380         CrntPlace = 0;
381         ExtCount = 0;
382     }
383
384     if (Extension != NULL) {
385         int i, Len;
386         Len = Extension[0];
387         for (i = 1; i <= Len; i++) {
388             (void)snprintf(&HexForm[CrntPlace * 3], 3,
389                            " %02x", Extension[i]);
390             (void)snprintf(&AsciiForm[CrntPlace], 3,
391                            "%c", MAKE_PRINTABLE(Extension[i]));
392             if (++CrntPlace == 16) {
393                 HexForm[CrntPlace * 3] = 0;
394                 AsciiForm[CrntPlace] = 0;
395                 printf("\n%05lx: %-49s  %-17s", ExtCount, HexForm, AsciiForm);
396                 ExtCount += 16;
397                 CrntPlace = 0;
398             }
399         }
400     }
401 }
402
403 /******************************************************************************
404  Print the given PixelBlock of length Len.
405  Save local information so printing can be performed continuously,
406  or reset to start state if Reset. If PixelBlock is NULL, output is flushed
407 ******************************************************************************/
408 static void PrintPixelBlock(GifByteType *PixelBlock, int Len, bool Reset)
409 {
410     static int CrntPlace = 0; 
411     static long ExtCount = 0;
412     static char HexForm[49], AsciiForm[17];
413     int i;
414
415     if (Reset || PixelBlock == NULL) {
416         if (PixelBlock == NULL) {
417             if (CrntPlace > 0) {
418                 HexForm[CrntPlace * 3] = 0;
419                 AsciiForm[CrntPlace] = 0;
420                 printf("\n%05lx: %-49s  %-17s\n", ExtCount, HexForm, AsciiForm);
421             }
422             else
423                 printf("\n");
424         }
425         CrntPlace = 0;
426         ExtCount = 0;
427         if (PixelBlock == NULL) return;
428     }
429
430     for (i = 0; i < Len; i++) {
431         (void)snprintf(&HexForm[CrntPlace * 3], 3,
432                        " %02x", PixelBlock[i]);
433         (void)snprintf(&AsciiForm[CrntPlace], 3,
434                        "%c", MAKE_PRINTABLE(PixelBlock[i]));
435         if (++CrntPlace == 16) {
436             HexForm[CrntPlace * 3] = 0;
437             AsciiForm[CrntPlace] = 0;
438             printf("\n%05lx: %-49s  %-17s", ExtCount, HexForm, AsciiForm);
439             ExtCount += 16;
440             CrntPlace = 0;
441         }
442     }
443 }
444
445 /******************************************************************************
446  Print the image as LZ codes (each 12bits), until EOF marker is reached.
447 ******************************************************************************/
448 static void PrintLZCodes(GifFileType *GifFile)
449 {
450     int Code, CrntPlace = 0;
451     long CodeCount = 0;
452
453     do {
454         if (CrntPlace == 0) printf("\n%05lx:", CodeCount);
455         if (DGifGetLZCodes(GifFile, &Code) == GIF_ERROR) {
456             PrintGifError(GifFile->Error);
457             exit(EXIT_FAILURE);
458         }
459         if (Code >= 0)
460             printf(" %03x", Code);            /* EOF Code is returned as -1. */
461         CodeCount++;
462         if (++CrntPlace >= 16) CrntPlace = 0;
463     }
464     while (Code >= 0);
465 }
466
467 /* end */