3 * Routines for image/gif media dissection
4 * Copyright 2003, 2004, Olivier Biot.
6 * $Id: packet-image-gif.c,v 1.4 2004/03/08 22:03:58 obiot Exp $
8 * Refer to the AUTHORS file or the AUTHORS section in the man page
9 * for contacting the author(s) of this file.
11 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@ethereal.com>
13 * Copyright 1998 Gerald Combs
15 * Compuserve GIF media decoding functionality provided by Olivier Biot.
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
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.
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.
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.
36 /* Edit this file with 4-space tabulation */
48 #ifdef NEED_SNPRINTF_H
49 # include "snprintf.h"
52 #include <epan/packet.h>
54 /* General-purpose debug logger.
55 * Requires double parentheses because of variable arguments of printf().
57 * Enable debug logging for GIF by defining AM_CFLAGS
58 * so that it contains "-DDEBUG_image_gif" or "-DDEBUG_image"
60 #if (defined(DEBUG_image_gif) || defined(DEBUG_image))
62 printf("%s:%u: ", __FILE__, __LINE__); \
69 #define PLURALIZE(x) ((x) == 1 ? "" : "s")
71 #define IMG_GIF "image-gif"
73 /************************** Variable declarations **************************/
75 static const value_string vals_true_false[] = {
81 static const value_string vals_extensions[] = {
82 { 0xF9, "Graphics Control" },
84 { 0xFF, "Application" },
85 { 0x01, "Plain Text" },
96 /* Initialize the protocol and registered fields */
97 static int proto_gif = -1;
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;
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;
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;
130 /* Trailer (end of GIF data stream) */
131 static gint hf_trailer = -1;
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;
141 /**************** GIF related declarations and definitions ****************/
144 /************************** Function prototypes **************************/
148 dissect_gif(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
151 proto_register_gif(void);
154 /****************** GIF protocol dissection functions ******************/
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".
162 dissect_gif(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
165 proto_tree *gif_tree; /* Main GIF tree */
166 proto_tree *subtree; /* Main GIF tree */
167 guint offset = 0, len = 0;
169 gboolean color_map_present;
170 guint8 color_resolution;
172 guint tvb_len = tvb_reported_length(tvb);
173 char *str = tvb_get_string(tvb, 0, 6);
176 /* Check whether we're processing a GIF object */
177 if (strcmp(str, "GIF87a") == 0) {
179 } else if (strcmp(str, "GIF89a") == 0) {
181 } else if (strncmp(str,"GIF", 3) == 0) {
182 version = GIF_UNKNOWN;
184 /* Not a GIF image! */
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);
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.
199 ti = proto_tree_add_item(tree, proto_gif, tvb, 0, -1, TRUE);
200 proto_item_append_text(ti, ", Version: %s", str);
202 gif_tree = proto_item_add_subtree(ti, ett_gif);
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>");
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);
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)
220 color_map_present = peek & 0x80;
221 color_resolution = 1 + ((peek & 0x60) >> 4);
222 image_bpp = 1 + (peek & 0x07);
224 ti = proto_tree_add_text(gif_tree, tvb, 10, 1,
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,
235 proto_tree_add_item(subtree, hf_global_color_resolution,
237 if (version == GIF_89a) {
238 proto_tree_add_item(subtree, hf_global_color_map_ordered,
241 proto_tree_add_item(subtree, hf_global_image_bpp,
244 /* Background color */
245 proto_tree_add_item(gif_tree, hf_background_color,
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
253 if (version == GIF_89a) {
254 peek = tvb_get_guint8(tvb, 12);
256 /* Only display if different from 0 */
257 proto_tree_add_uint_format(gif_tree, hf_pixel_aspect_ratio,
259 "%u, yields an aspect ratio of (15 + %u) / 64 = %.2f",
260 peek, peek, (float)(15 + peek) / 64.0);
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,
276 /* From now on, a set of images prefixed with the image separator
277 * character 0x2C (',') will appear in the byte stream. Each image
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)
297 * NOTE that the GIF specification only requires that:
298 * image left + image width <= screen width
299 * image top + image height <= screen height
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).
310 * This is a synchronization method, based on the final character 0xB3
311 * (';') at the end of an image
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).
323 * NOTE that the GIF extension block can only appear at the following
325 * - Immediately before an Image Descriptor
326 * - Before the GIF termination character
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:
333 * 1 byte : extension_label
336 ti = proto_tree_add_item(gif_tree, hf_extension,
337 tvb, offset, 1, TRUE);
338 subtree = proto_item_add_subtree(ti, ett_extension);
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>"));
348 /* Read length of data block */
349 len = tvb_get_guint8(tvb, offset);
350 proto_tree_add_text(subtree, tvb,
352 "Data block (length = %u)", len);
354 item_len += (1 + len);
356 proto_item_set_len(ti, item_len);
357 } else if (peek == 0x2C) { /* Image separator */
358 proto_tree *subtree2;
360 guint32 item_len = 11; /* Fixed header consisting of:
362 * 2 bytes: image_left
364 * 2 bytes: image_width
365 * 2 bytes: image height
366 * 1 byte : packed bit field
367 * 1 byte : image code size
370 ti = proto_tree_add_item(gif_tree, hf_image,
371 tvb, offset, 1, TRUE);
372 subtree = proto_item_add_subtree(ti, ett_image);
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;
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);
389 ti2 = proto_tree_add_text(subtree, tvb, offset, 1,
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);
406 proto_tree_add_item(subtree2, hf_global_image_bpp,
407 tvb, offset, 1, TRUE);
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);
424 proto_tree_add_item(subtree, hf_image_code_size,
425 tvb, offset, 1, TRUE);
428 /* Read length of data block */
429 len = tvb_get_guint8(tvb, offset);
430 proto_tree_add_text(subtree, tvb,
432 "Data block (length = %u)", len);
434 item_len += (1 + len);
436 proto_item_set_len(ti, item_len);
438 /* GIF processing stops at this very byte */
439 proto_tree_add_item(gif_tree, hf_trailer,
440 tvb, offset, 1, TRUE);
448 /****************** Register the protocol with Ethereal ******************/
451 /* This format is required because a script is used to build the C function
452 * that calls the protocol registration. */
455 proto_register_gif(void)
458 * Setup list of header fields.
460 static hf_register_info hf[] = {
462 * GIF signature and version
467 FT_STRING, BASE_NONE, NULL, 0x00,
474 * Logical screen descriptor
478 IMG_GIF ".screen.width",
479 FT_UINT16, BASE_DEC, NULL, 0x00,
486 IMG_GIF ".screen.height",
487 FT_UINT16, BASE_DEC, NULL, 0x00,
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",
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.",
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.",
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.",
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.",
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.",
540 { &hf_global_color_map,
541 { "Global color map",
542 IMG_GIF ".global.color_map",
543 FT_BYTES, BASE_NONE, NULL, 0x00,
550 * Local color map (part of image)
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",
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.",
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.",
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.",
584 { &hf_local_color_map,
586 IMG_GIF ".local.color_map",
587 FT_BYTES, BASE_NONE, NULL, 0x00,
598 IMG_GIF ".extension",
599 FT_NONE, BASE_NONE, NULL, 0x00,
604 { &hf_extension_label,
606 IMG_GIF ".extension.label",
607 FT_UINT8, BASE_HEX, VALS(vals_extensions), 0x00,
619 FT_NONE, BASE_NONE, NULL, 0x80,
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.",
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.",
642 IMG_GIF ".image.width",
643 FT_UINT16, BASE_DEC, NULL, 0x00,
650 IMG_GIF ".image.height",
651 FT_UINT16, BASE_DEC, NULL, 0x00,
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.",
668 { "Trailer (End of the GIF stream)",
670 FT_NONE, BASE_NONE, NULL, 0x00,
671 "This byte tells the decoder that the data stream is finished.",
677 /* Setup protocol subtree array */
678 static gint *ett[] = {
686 /* Register the protocol name and description */
687 proto_gif = proto_register_protocol(
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));
698 register_dissector("image-gif", dissect_gif, proto_gif);
703 proto_reg_handoff_gif(void)
705 dissector_handle_t gif_handle;
707 gif_handle = create_dissector_handle(dissect_gif, proto_gif);
709 /* Register the GIF media type */
710 dissector_add_string("media_type", "image/gif", gif_handle);