update to netlogon to show DsrGetDcNameEx2() Client account name, domain name and...
[obnox/wireshark/wip.git] / packet-image-gif.c
1 /* packet-image-gif.c
2  *
3  * Routines for image/gif media dissection
4  * Copyright 2003, 2004, Olivier Biot.
5  *
6  * $Id: packet-image-gif.c,v 1.4 2004/03/08 22:03:58 obiot Exp $
7  *
8  * Refer to the AUTHORS file or the AUTHORS section in the man page
9  * for contacting the author(s) of this file.
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@ethereal.com>
13  * Copyright 1998 Gerald Combs
14  *
15  * Compuserve GIF media decoding functionality provided by Olivier Biot.
16  * 
17  * The two GIF specifications are found at several locations, such as W3C:
18  * http://www.w3.org/Graphics/GIF/spec-gif87.txt
19  * http://www.w3.org/Graphics/GIF/spec-gif89a.txt
20  * 
21  * This program is free software; you can redistribute it and/or
22  * modify it under the terms of the GNU General Public License
23  * as published by the Free Software Foundation; either version 2
24  * of the License, or (at your option) any later version.
25  * 
26  * This program is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29  * GNU General Public License for more details.
30  * 
31  * You should have received a copy of the GNU General Public License
32  * along with this program; if not, write to the Free Software
33  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34  */
35
36 /* Edit this file with 4-space tabulation */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <glib.h>
47
48 #ifdef NEED_SNPRINTF_H
49 # include "snprintf.h"
50 #endif
51
52 #include <epan/packet.h>
53
54 /* General-purpose debug logger.
55  * Requires double parentheses because of variable arguments of printf().
56  *
57  * Enable debug logging for GIF by defining AM_CFLAGS
58  * so that it contains "-DDEBUG_image_gif" or "-DDEBUG_image"
59  */
60 #if (defined(DEBUG_image_gif) || defined(DEBUG_image))
61 #define DebugLog(x) \
62         printf("%s:%u: ", __FILE__, __LINE__); \
63         printf x; \
64         fflush(stdout)
65 #else
66 #define DebugLog(x) ;
67 #endif
68
69 #define PLURALIZE(x) ((x) == 1 ? "" : "s")
70
71 #define IMG_GIF "image-gif"
72
73 /************************** Variable declarations **************************/
74
75 static const value_string vals_true_false[] = {
76         { 0, "False" },
77         { 1, "True" },
78         { 0, NULL },
79 };
80
81 static const value_string vals_extensions[] = {
82         { 0xF9, "Graphics Control" },
83         { 0xFE, "Comment" },
84         { 0xFF, "Application" },
85         { 0x01, "Plain Text" },
86         { 0x00, NULL, },
87 };
88
89 enum {
90         GIF_UNKNOWN = 0,
91         GIF_87a = 0x87,
92         GIF_89a = 0x89,
93         GIF_ERROR = 0xFF
94 };
95
96 /* Initialize the protocol and registered fields */
97 static int proto_gif = -1;
98
99 /* header fields */
100 /* GIF signature */
101 static gint hf_version = -1;
102 /* Screen descriptor */
103 static gint hf_screen_width = -1;
104 static gint hf_screen_height = -1;
105 static gint hf_global_color_map_present = -1;
106 static gint hf_global_color_resolution = -1;
107 static gint hf_global_color_map_ordered = -1; /* GIF89a */
108 static gint hf_global_image_bpp = -1;
109 /* Only makes sense if the global color map is present: */
110 static gint hf_background_color = -1;
111 static gint hf_pixel_aspect_ratio = -1; /* GIF89a */
112 static gint hf_global_color_map = -1;
113
114 /* Image descriptor */
115 static gint hf_image_left = -1;
116 static gint hf_image_top = -1;
117 static gint hf_image_width = -1;
118 static gint hf_image_height = -1;
119 static gint hf_local_color_map_present = -1;
120 static gint hf_local_color_resolution = -1;
121 static gint hf_local_color_map_ordered = -1; /* GIF89a */
122 static gint hf_local_image_bpp = -1;
123 static gint hf_local_color_map = -1;
124
125 static gint hf_extension = -1;
126 static gint hf_extension_label = -1;
127 static gint hf_image = -1;
128 static gint hf_image_code_size = -1;
129
130 /* Trailer (end of GIF data stream) */
131 static gint hf_trailer = -1;
132
133 /* Initialize the subtree pointers */
134 static gint ett_gif = -1;
135 static gint ett_global_flags = -1;
136 static gint ett_local_flags = -1;
137 static gint ett_extension = -1;
138 static gint ett_image = -1;
139
140
141 /**************** GIF related declarations and definitions ****************/
142
143
144 /************************** Function prototypes **************************/
145
146
147 static void
148 dissect_gif(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
149
150 void
151 proto_register_gif(void);
152
153
154 /****************** GIF protocol dissection functions ******************/
155
156 /* There are two Compuserve GIF standards: GIF87a and GIF89a. GIF image files
157  * always convey their version in the first 6 bytes, written as an US-ASCII
158  * string representation of the version: "GIF87a" or "GIF89a".
159  */
160
161 static void
162 dissect_gif(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
163 {
164         proto_item *ti;
165         proto_tree *gif_tree; /* Main GIF tree */
166         proto_tree *subtree; /* Main GIF tree */
167         guint offset = 0, len = 0;
168         guint8 peek;
169         gboolean color_map_present;
170         guint8 color_resolution;
171         guint8 image_bpp;
172         guint tvb_len = tvb_reported_length(tvb);
173         char *str = tvb_get_string(tvb, 0, 6);
174         guint8 version;
175
176         /* Check whether we're processing a GIF object */
177         if (strcmp(str, "GIF87a") == 0) {
178                 version = GIF_87a;
179         } else if (strcmp(str, "GIF89a") == 0) {
180                 version = GIF_89a;
181         } else if (strncmp(str,"GIF", 3) == 0) {
182                 version = GIF_UNKNOWN;
183         } else {
184                 /* Not a GIF image! */
185                 version = GIF_ERROR;
186                 g_free(str);
187                 return;
188         }
189         /* Add summary to INFO column if it is enabled */
190         if (check_col(pinfo->cinfo, COL_INFO))
191                 col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", str);
192
193         /* In order to speed up dissection, do not add items to the protocol tree
194          * if it is not visible. However, compute the values that are needed for
195          * correct protocol dissection if they have more meaning than just adding
196          * items to the protocol tree.
197          */
198         if (tree) {
199                 ti = proto_tree_add_item(tree, proto_gif, tvb, 0, -1, TRUE);
200                 proto_item_append_text(ti, ", Version: %s", str);
201                 g_free(str);
202                 gif_tree = proto_item_add_subtree(ti, ett_gif);
203                 /* GIF signature */
204                 ti = proto_tree_add_item(gif_tree, hf_version, tvb, 0, 6, TRUE);
205                 if (version == GIF_UNKNOWN) {
206                         proto_item_append_text(ti, " <Error: unknown GIF version>");
207                 }
208                 /* Screen descriptor */
209                 proto_tree_add_item(gif_tree, hf_screen_width, tvb, 6, 2, TRUE);
210                 proto_tree_add_item(gif_tree, hf_screen_height, tvb, 8, 2, TRUE);
211
212                 peek = tvb_get_guint8(tvb, 10);
213                 /* Bitfield gccc 0ppp
214                  *                      g... .... : global color map present
215                  *                      .ccc .... : color resolution in bits (add one)
216                  *                      .... 0... : GIF87a - reserved (no use)
217                  *                                              GIF89a - ordered (most important color 1st)
218                  *                      .... .ppp : bits per pixel in image (add one)
219                  */
220                 color_map_present = peek & 0x80;
221                 color_resolution = 1 + ((peek & 0x60) >> 4);
222                 image_bpp = 1 + (peek & 0x07);
223         
224                 ti = proto_tree_add_text(gif_tree, tvb, 10, 1,
225                                 "Global settings:");
226                 if (color_map_present)
227                         proto_item_append_text(ti, " (Global color table present)");
228                 proto_item_append_text(ti,
229                                 " (%u bit%s per color) (%u bit%s per pixel)",
230                                 color_resolution, PLURALIZE(color_resolution),
231                                 image_bpp, PLURALIZE(image_bpp));
232                 subtree = proto_item_add_subtree(ti, ett_global_flags);
233                 proto_tree_add_item(subtree, hf_global_color_map_present,
234                                 tvb, 10, 1, TRUE);
235                 proto_tree_add_item(subtree, hf_global_color_resolution,
236                                 tvb, 10, 1, TRUE);
237                 if (version == GIF_89a) {
238                         proto_tree_add_item(subtree, hf_global_color_map_ordered,
239                                         tvb, 10, 1, TRUE);
240                 }
241                 proto_tree_add_item(subtree, hf_global_image_bpp,
242                                 tvb, 10, 1, TRUE);
243
244                 /* Background color */
245                 proto_tree_add_item(gif_tree, hf_background_color,
246                                 tvb, 11, 1, TRUE);
247
248                 /* byte at offset 12 is 0x00 - reserved in GIF87a but encodes the
249                  * pixel aspect ratio in GIF89a as:
250                  *              aspect-ratio = (15 + pixel-aspect-ratio) / 64
251                  * where the aspect-ratio is not computed if pixel-aspect-ratio == 0
252                  */
253                 if (version == GIF_89a) {
254                         peek = tvb_get_guint8(tvb, 12);
255                         if (peek) {
256                                 /* Only display if different from 0 */
257                                 proto_tree_add_uint_format(gif_tree, hf_pixel_aspect_ratio,
258                                                 tvb, 12, 1, peek,
259                                                 "%u, yields an aspect ratio of (15 + %u) / 64 = %.2f",
260                                                 peek, peek, (float)(15 + peek) / 64.0);
261                         }
262                 }
263
264                 /* Global color map
265                  * If present, it takes 2 ^ (image_bpp) byte tuples (R, G, B)
266                  * that contain the Red, Green and Blue intensity of the colors
267                  * in the Global Color Map */
268                 if (color_map_present) {
269                         len = 3 * (1 << image_bpp);
270                         proto_tree_add_item(gif_tree, hf_global_color_map,
271                                         tvb, 13, len, TRUE);
272                 } else {
273                         len = 0;
274                 }
275                 offset = 13 + len;
276                 /* From now on, a set of images prefixed with the image separator
277                  * character 0x2C (',') will appear in the byte stream. Each image
278                  * hence consists of:
279                  * - The image separator character 0x2C
280                  * - Image left (16 bits LSB first): pixels from left border
281                  * - Image top (16 bits LSB first): pixels from to border
282                  * - Image width (16 bits LSB first)
283                  * - Image height (16 bits LSB first)
284                  * - A bitfield MI00 0ppp
285                  *                              M... .... : Use global color map if unset (ignore ppp);
286                  *                                                      if set a local color map will be defined.
287                  *                              .I.. .... : Image formatted in interlaced order if set;
288                  *                                                      otherwise it is plain sequential order
289                  *                              ..0. .... : GIF87a - Reserved
290                  *                              ..s. ....       GIF89a - Set if local color map is ordered
291                  *                              ...0 0... : Reserved
292                  *                              .... .ppp : bits per pixel in image (add one)
293                  * - If the local color map bit is set, then a local color table follows
294                  *   with length = 3 x 2 ^ (1 + bits per pixel)
295                  * - The raster data
296                  *
297                  * NOTE that the GIF specification only requires that:
298                  *              image left + image width  <= screen width
299                  *              image top  + image height <= screen height
300                  *
301                  * The Raster Data is encoded as follows:
302                  * - Code size (1 byte)
303                  * - Blocks consisting of
304                  *              o Byte count (1 byte): number of bytes in the block
305                  *              o Data bytes: as many as specified in the byte count
306                  *       End of data is given with an empty block (byte count == 0).
307                  *
308                  *
309                  * GIF terminator
310                  * This is a synchronization method, based on the final character 0xB3
311                  * (';') at the end of an image
312                  *
313                  *
314                  * GIF extension
315                  * This is a block of data encoded as:
316                  * - The GIF extension block introducer 0x21 ('!')
317                  * - The extension function code (1 byte)
318                  * - Blocks consisting of
319                  *              o Byte count (1 byte): number of bytes in the block
320                  *              o Data bytes: as many as specified in the byte count
321                  *       End of data is given with an empty block (byte count == 0).
322                  *
323                  * NOTE that the GIF extension block can only appear at the following
324                  * locations:
325                  * - Immediately before an Image Descriptor
326                  * - Before the GIF termination character
327                  */
328                 while (offset < tvb_len) {
329                         peek = tvb_get_guint8(tvb, offset);
330                         if (peek == 0x21) { /* GIF extension block */
331                                 guint32 item_len = 2;   /* Fixed header consisting of:
332                                                                                  *      1 byte : 0x21
333                                                                                  *      1 byte : extension_label
334                                                                                  */
335
336                                 ti = proto_tree_add_item(gif_tree, hf_extension,
337                                                 tvb, offset, 1, TRUE);
338                                 subtree = proto_item_add_subtree(ti, ett_extension);
339                                 offset++;
340                                 proto_tree_add_item(subtree, hf_extension_label,
341                                                 tvb, offset, 1, TRUE);
342                                 peek = tvb_get_guint8(tvb, offset);
343                                 proto_item_append_text(ti, ": %s",
344                                                 val_to_str(peek, vals_extensions,
345                                                         "<Warning: Unknown extension 0x%02X>"));
346                                 offset++;
347                                 do {
348                                         /* Read length of data block */
349                                         len = tvb_get_guint8(tvb, offset);
350                                         proto_tree_add_text(subtree, tvb,
351                                                         offset, 1 + len,
352                                                         "Data block (length = %u)", len);
353                                         offset += (1 + len);
354                                         item_len += (1 + len);
355                                 } while (len > 0);
356                                 proto_item_set_len(ti, item_len);
357                         } else if (peek == 0x2C) { /* Image separator */
358                                 proto_tree *subtree2;
359                                 proto_item *ti2;
360                                 guint32 item_len = 11;  /* Fixed header consisting of:
361                                                                                  *      1 byte : 0x2C
362                                                                                  *      2 bytes: image_left
363                                                                                  *      2 bytes: image_top
364                                                                                  *      2 bytes: image_width
365                                                                                  *      2 bytes: image height
366                                                                                  *      1 byte : packed bit field
367                                                                                  *      1 byte : image code size
368                                                                                  */
369
370                                 ti = proto_tree_add_item(gif_tree, hf_image,
371                                                 tvb, offset, 1, TRUE);
372                                 subtree = proto_item_add_subtree(ti, ett_image);
373                                 offset++;
374                                 /* Screen descriptor */
375                                 proto_tree_add_item(subtree, hf_image_left,
376                                                 tvb, offset, 2, TRUE); offset += 2;
377                                 proto_tree_add_item(subtree, hf_image_top,
378                                                 tvb, offset, 2, TRUE); offset += 2;
379                                 proto_tree_add_item(subtree, hf_image_width,
380                                                 tvb, offset, 2, TRUE); offset += 2;
381                                 proto_tree_add_item(subtree, hf_image_height,
382                                                 tvb, offset, 2, TRUE); offset += 2;
383                                 /* bit field */
384                                 peek = tvb_get_guint8(tvb, offset);
385                                 color_map_present = peek & 0x80;
386                                 color_resolution = 1 + ((peek & 0x60) >> 4);
387                                 image_bpp = 1 + (peek & 0x07);
388         
389                                 ti2 = proto_tree_add_text(subtree, tvb, offset, 1,
390                                                 "Local settings:");
391                                 if (color_map_present)
392                                         proto_item_append_text(ti2, " (Local color table present)");
393                                 proto_item_append_text(ti2,
394                                                 " (%u bit%s per color) (%u bit%s per pixel)",
395                                                 color_resolution, PLURALIZE(color_resolution),
396                                                 image_bpp, PLURALIZE(image_bpp));
397                                 subtree2 = proto_item_add_subtree(ti2, ett_local_flags);
398                                 proto_tree_add_item(subtree2, hf_local_color_map_present,
399                                                 tvb, offset, 1, TRUE);
400                                 proto_tree_add_item(subtree2, hf_local_color_resolution,
401                                                 tvb, offset, 1, TRUE);
402                                 if (version == GIF_89a) {
403                                         proto_tree_add_item(subtree2, hf_local_color_map_ordered,
404                                                         tvb, offset, 1, TRUE);
405                                 }
406                                 proto_tree_add_item(subtree2, hf_global_image_bpp,
407                                                 tvb, offset, 1, TRUE);
408                                 offset++;
409
410                                 /* Local color map
411                                  * If present, it takes 2 ^ (image_bpp) byte tuples (R, G, B)
412                                  * that contain the Red, Green and Blue intensity of the colors
413                                  * in the Local Color Map */
414                                 if (color_map_present) {
415                                         len = 3 * (1 << image_bpp);
416                                         proto_tree_add_item(subtree, hf_local_color_map,
417                                                         tvb, offset, len, TRUE);
418                                 } else {
419                                         len = 0;
420                                 }
421                                 offset += len;
422                                 item_len += len;
423
424                                 proto_tree_add_item(subtree, hf_image_code_size,
425                                                 tvb, offset, 1, TRUE);
426                                 offset++;
427                                 do {
428                                         /* Read length of data block */
429                                         len = tvb_get_guint8(tvb, offset);
430                                         proto_tree_add_text(subtree, tvb,
431                                                         offset, 1 + len,
432                                                         "Data block (length = %u)", len);
433                                         offset += 1 + len;
434                                         item_len += (1 + len);
435                                 } while (len > 0);
436                                 proto_item_set_len(ti, item_len);
437                         } else {
438                                 /* GIF processing stops at this very byte */
439                                 proto_tree_add_item(gif_tree, hf_trailer,
440                                                 tvb, offset, 1, TRUE);
441                                 break;
442                         }
443                 } /* while */
444         }
445 }
446
447
448 /****************** Register the protocol with Ethereal ******************/
449
450
451 /* This format is required because a script is used to build the C function
452  * that calls the protocol registration. */
453
454 void
455 proto_register_gif(void)
456 {
457         /*
458          * Setup list of header fields.
459          */
460         static hf_register_info hf[] = {
461                 /*
462                  * GIF signature and version
463                  */
464                 { &hf_version,
465                         {       "Version",
466                                 IMG_GIF ".version",
467                                 FT_STRING, BASE_NONE, NULL, 0x00,
468                                 "GIF Version",
469                                 HFILL
470                         }
471                 },
472
473                 /*
474                  * Logical screen descriptor
475                  */
476                 { &hf_screen_width,
477                         {       "Screen width",
478                                 IMG_GIF ".screen.width",
479                                 FT_UINT16, BASE_DEC, NULL, 0x00,
480                                 "Screen width",
481                                 HFILL
482                         }
483                 },
484                 { &hf_screen_height,
485                         {       "Screen height",
486                                 IMG_GIF ".screen.height",
487                                 FT_UINT16, BASE_DEC, NULL, 0x00,
488                                 "Screen height",
489                                 HFILL
490                         }
491                 },
492                 { &hf_global_color_map_present,
493                         {       "Global color map is present",
494                                 IMG_GIF ".global.color_map.present",
495                                 FT_UINT8, BASE_DEC, VALS(vals_true_false), 0x80,
496                                 "Indicates if the global color map is present",
497                                 HFILL
498                         }
499                 },
500                 { &hf_global_color_resolution,
501                         {       "Bits per color minus 1",
502                                 IMG_GIF ".global.color_bpp",
503                                 FT_UINT8, BASE_DEC, NULL, 0x70,
504                                 "The number of bits per color is one plus the field value.",
505                                 HFILL
506                         }
507                 },
508                 { &hf_global_color_map_ordered,
509                         {       "Global color map is ordered",
510                                 IMG_GIF ".global.color_map.ordered",
511                                 FT_UINT8, BASE_DEC, VALS(vals_true_false), 0x08,
512                                 "Indicates whether the global color map is ordered.",
513                                 HFILL
514                         }
515                 },
516                 { &hf_global_image_bpp,
517                         {       "Image bits per pixel minus 1",
518                                 IMG_GIF ".global.bpp",
519                                 FT_UINT8, BASE_DEC, NULL, 0x07,
520                                 "The number of bits per pixel is one plus the field value.",
521                                 HFILL
522                         }
523                 },
524                 { &hf_background_color,
525                         {       "Background color index",
526                                 IMG_GIF ".image_background_index",
527                                 FT_UINT8, BASE_DEC, NULL, 0x00,
528                                 "Index of the background color in the color map.",
529                                 HFILL
530                         }
531                 },
532                 { &hf_pixel_aspect_ratio,
533                         {       "Global pixel aspect ratio",
534                                 IMG_GIF ".global.pixel_aspect_ratio",
535                                 FT_UINT8, BASE_DEC, NULL, 0x00,
536                                 "Gives an approximate value of the aspect ratio of the pixels.",
537                                 HFILL
538                         }
539                 },
540                 { &hf_global_color_map,
541                         {       "Global color map",
542                                 IMG_GIF ".global.color_map",
543                                 FT_BYTES, BASE_NONE, NULL, 0x00,
544                                 "Global color map.",
545                                 HFILL
546                         }
547                 },
548
549                 /*
550                  * Local color map (part of image)
551                  */
552                 { &hf_local_color_map_present,
553                         {       "Local color map is present",
554                                 IMG_GIF ".local.color_map.present",
555                                 FT_UINT8, BASE_DEC, VALS(vals_true_false), 0x80,
556                                 "Indicates if the local color map is present",
557                                 HFILL
558                         }
559                 },
560                 { &hf_local_color_resolution,
561                         {       "Bits per color minus 1",
562                                 IMG_GIF ".local.color_bpp",
563                                 FT_UINT8, BASE_DEC, NULL, 0x70,
564                                 "The number of bits per color is one plus the field value.",
565                                 HFILL
566                         }
567                 },
568                 { &hf_local_color_map_ordered,
569                         {       "Local color map is ordered",
570                                 IMG_GIF ".local.color_map.ordered",
571                                 FT_UINT8, BASE_DEC, VALS(vals_true_false), 0x08,
572                                 "Indicates whether the local color map is ordered.",
573                                 HFILL
574                         }
575                 },
576                 { &hf_local_image_bpp,
577                         {       "Image bits per pixel minus 1",
578                                 IMG_GIF ".local.bpp",
579                                 FT_UINT8, BASE_DEC, NULL, 0x07,
580                                 "The number of bits per pixel is one plus the field value.",
581                                 HFILL
582                         }
583                 },
584                 { &hf_local_color_map,
585                         {       "Local color map",
586                                 IMG_GIF ".local.color_map",
587                                 FT_BYTES, BASE_NONE, NULL, 0x00,
588                                 "Local color map.",
589                                 HFILL
590                         }
591                 },
592
593                 /*
594                  * Extension
595                  */
596                 { &hf_extension,
597                         {       "Extension",
598                                 IMG_GIF ".extension",
599                                 FT_NONE, BASE_NONE, NULL, 0x00,
600                                 "Extension.",
601                                 HFILL
602                         }
603                 },
604                 { &hf_extension_label,
605                         {       "Extension label",
606                                 IMG_GIF ".extension.label",
607                                 FT_UINT8, BASE_HEX, VALS(vals_extensions), 0x00,
608                                 "Extension label.",
609                                 HFILL
610                         }
611                 },
612
613                 /*
614                  * Image
615                  */
616                 { &hf_image,
617                         {       "Image",
618                                 IMG_GIF ".image",
619                                 FT_NONE, BASE_NONE, NULL, 0x80,
620                                 "Image.",
621                                 HFILL
622                         }
623                 },
624                 { &hf_image_left,
625                         {       "Image left position",
626                                 IMG_GIF ".image.left",
627                                 FT_UINT16, BASE_DEC, NULL, 0x00,
628                                 "Offset between left of Screen and left of Image.",
629                                 HFILL
630                         }
631                 },
632                 { &hf_image_top,
633                         {       "Image top position",
634                                 IMG_GIF ".image.top",
635                                 FT_UINT16, BASE_DEC, NULL, 0x00,
636                                 "Offset between top of Screen and top of Image.",
637                                 HFILL
638                         }
639                 },
640                 { &hf_image_width,
641                         {       "Image width",
642                                 IMG_GIF ".image.width",
643                                 FT_UINT16, BASE_DEC, NULL, 0x00,
644                                 "Image width.",
645                                 HFILL
646                         }
647                 },
648                 { &hf_image_height,
649                         {       "Image height",
650                                 IMG_GIF ".image.height",
651                                 FT_UINT16, BASE_DEC, NULL, 0x00,
652                                 "Image height.",
653                                 HFILL
654                         }
655                 },
656                 { &hf_image_code_size,
657                         {       "LZW minimum code size",
658                                 IMG_GIF ".image.code_size",
659                                 FT_UINT8, BASE_DEC, NULL, 0x00,
660                                 "Minimum code size for the LZW compression.",
661                                 HFILL
662                         }
663                 },
664                 /*
665                  * Trailer
666                  */
667                 { &hf_trailer,
668                         {       "Trailer (End of the GIF stream)",
669                                 IMG_GIF ".end",
670                                 FT_NONE, BASE_NONE, NULL, 0x00,
671                                 "This byte tells the decoder that the data stream is finished.",
672                                 HFILL
673                         }
674                 },
675         };
676
677         /* Setup protocol subtree array */
678         static gint *ett[] = {
679                 &ett_gif,
680                 &ett_global_flags,
681                 &ett_local_flags,
682                 &ett_extension,
683                 &ett_image,
684         };
685
686         /* Register the protocol name and description */
687         proto_gif = proto_register_protocol(
688                         "Compuserve GIF",
689                         "GIF image",
690                         IMG_GIF
691         );
692
693         /* Required function calls to register the header fields
694          * and subtrees used */
695         proto_register_field_array(proto_gif, hf, array_length(hf));
696         proto_register_subtree_array(ett, array_length(ett));
697
698         register_dissector("image-gif", dissect_gif, proto_gif);
699 }
700
701
702 void
703 proto_reg_handoff_gif(void)
704 {
705         dissector_handle_t gif_handle;
706
707         gif_handle = create_dissector_handle(dissect_gif, proto_gif);
708
709         /* Register the GIF media type */
710         dissector_add_string("media_type", "image/gif", gif_handle);
711 }