521d90a7fa01fb65f419e5b38122ede608392c12
[obnox/wireshark/wip.git] / epan / dissectors / packet-image-jfif.c
1 /* packet-image-jfif.c
2  *
3  * Routines for JFIF image/jpeg media dissection
4  * Copyright 2004, Olivier Biot.
5  *
6  * $Id$
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  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * JFIF media decoding functionality provided by Olivier Biot.
16  *
17  * The JFIF specifications are found at several locations, such as:
18  * http://www.jpeg.org/public/jfif.pdf
19  * http://www.w3.org/Graphics/JPEG/itu-t81.pdf
20  *
21  * The Exif specifications are found at several locations, such as:
22  * http://www.exif.org/
23  *
24  * This program is free software; you can redistribute it and/or
25  * modify it under the terms of the GNU General Public License
26  * as published by the Free Software Foundation; either version 2
27  * of the License, or (at your option) any later version.
28  *
29  * This program is distributed in the hope that it will be useful,
30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32  * GNU General Public License for more details.
33  *
34  * You should have received a copy of the GNU General Public License
35  * along with this program; if not, write to the Free Software
36  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37  */
38
39 /* Edit this file with 4-space tabulation */
40
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 #include <glib.h>
50
51 #include <epan/packet.h>
52
53 /* General-purpose debug logger.
54  * Requires double parentheses because of variable arguments of printf().
55  *
56  * Enable debug logging for JFIF by defining AM_CFLAGS
57  * so that it contains "-DDEBUG_image_jfif" or "-DDEBUG_image"
58  */
59 #if (defined(DEBUG_image_jfif) || defined(DEBUG_image))
60 #define DebugLog(x) \
61         g_print("%s:%u: ", __FILE__, __LINE__); \
62         g_print x
63 #else
64 #define DebugLog(x) ;
65 #endif
66
67 #define IMG_JFIF "image-jfif"
68
69 /************************** Variable declarations **************************/
70
71 #define MARKER_TEM              0xFF01
72
73 /* 0xFF02 -- 0xFFBF are reserved */
74
75 #define MARKER_SOF0             0xFFC0
76 #define MARKER_SOF1             0xFFC1
77 #define MARKER_SOF2             0xFFC2
78 #define MARKER_SOF3             0xFFC3
79
80 #define MARKER_DHT              0xFFC4
81
82 #define MARKER_SOF5             0xFFC5
83 #define MARKER_SOF6             0xFFC6
84 #define MARKER_SOF7             0xFFC7
85 #define MARKER_SOF8             0xFFC8
86 #define MARKER_SOF9             0xFFC9
87 #define MARKER_SOF10    0xFFCA
88 #define MARKER_SOF11    0xFFCB
89
90 #define MARKER_DAC              0xFFCC
91
92 #define MARKER_SOF13    0xFFCD
93 #define MARKER_SOF14    0xFFCE
94 #define MARKER_SOF15    0xFFCF
95
96 #define MARKER_RST0             0xFFD0
97 #define MARKER_RST1             0xFFD1
98 #define MARKER_RST2             0xFFD2
99 #define MARKER_RST3             0xFFD3
100 #define MARKER_RST4             0xFFD4
101 #define MARKER_RST5             0xFFD5
102 #define MARKER_RST6             0xFFD6
103 #define MARKER_RST7             0xFFD7
104
105 #define MARKER_FFDB             0xFFDB
106 #define MARKER_SOI              0xFFD8
107 #define MARKER_EOI              0xFFD9
108 #define MARKER_SOS              0xFFDA
109 #define MARKER_DQT              0xFFDB
110 #define MARKER_DNL              0xFFDC
111 #define MARKER_DRI              0xFFDD
112 #define MARKER_DHP              0xFFDE
113 #define MARKER_EXP              0xFFDF
114
115 #define MARKER_APP0             0xFFE0
116 #define MARKER_APP1             0xFFE1
117 #define MARKER_APP2             0xFFE2
118 #define MARKER_APP3             0xFFE3
119 #define MARKER_APP4             0xFFE4
120 #define MARKER_APP5             0xFFE5
121 #define MARKER_APP6             0xFFE6
122 #define MARKER_APP7             0xFFE7
123 #define MARKER_APP8             0xFFE8
124 #define MARKER_APP9             0xFFE9
125 #define MARKER_APP10    0xFFEA
126 #define MARKER_APP11    0xFFEB
127 #define MARKER_APP12    0xFFEC
128 #define MARKER_APP13    0xFFED
129 #define MARKER_APP14    0xFFEE
130 #define MARKER_APP15    0xFFEF
131
132 #define MARKER_JPG0             0xFFF0
133 #define MARKER_JPG1             0xFFF1
134 #define MARKER_JPG2             0xFFF2
135 #define MARKER_JPG3             0xFFF3
136 #define MARKER_JPG4             0xFFF4
137 #define MARKER_JPG5             0xFFF5
138 #define MARKER_JPG6             0xFFF6
139 #define MARKER_JPG7             0xFFF7
140 #define MARKER_JPG8             0xFFF8
141 #define MARKER_JPG9             0xFFF9
142 #define MARKER_JPG10    0xFFFA
143 #define MARKER_JPG11    0xFFFB
144 #define MARKER_JPG12    0xFFFC
145 #define MARKER_JPG13    0xFFFD
146
147 #define MARKER_COM              0xFFFE
148
149 #define marker_has_length(marker) ( ! ( \
150            ((marker) == MARKER_TEM) \
151         || ((marker) == MARKER_SOI) \
152         || ((marker) == MARKER_EOI) \
153         || ( ((marker) >= MARKER_RST0) && ((marker) <= MARKER_RST7) ) \
154         ) )
155
156
157 static const value_string vals_marker[] = {
158         { MARKER_TEM,   "Reserved - For temporary private use in arithmetic coding" },
159         { MARKER_SOF0,  "Start of Frame (non-differential, Huffman coding) - Baseline DCT" },
160         { MARKER_SOF1,  "Start of Frame (non-differential, Huffman coding) - Extended sequential DCT" },
161         { MARKER_SOF2,  "Start of Frame (non-differential, Huffman coding) - Progressive DCT" },
162         { MARKER_SOF3,  "Start of Frame (non-differential, Huffman coding) - Lossless (sequential)" },
163         { MARKER_DHT,   "Define Huffman table(s)" },
164         { MARKER_SOF5,  "Start of Frame (differential, Huffman coding) - Differential sequential DCT" },
165         { MARKER_SOF6,  "Start of Frame (differential, Huffman coding) - Differential progressive DCT" },
166         { MARKER_SOF7,  "Start of Frame (differential, Huffman coding) - Differential lossless (sequential)" },
167         { MARKER_SOF8,  "Start of Frame (non-differential, arithmetic coding) - Reserved for JPEG extensions" },
168         { MARKER_SOF9,  "Start of Frame (non-differential, arithmetic coding) - Extended sequential DCT" },
169         { MARKER_SOF10, "Start of Frame (non-differential, arithmetic coding) - Progressive DCT" },
170         { MARKER_SOF11, "Start of Frame (non-differential, arithmetic coding) - Lossless (sequential)" },
171         { MARKER_DAC,   "Define arithmetic coding conditioning(s)" },
172         { MARKER_SOF13, "Start of Frame (differential, arithmetic coding) - Differential sequential DCT" },
173         { MARKER_SOF14, "Start of Frame (differential, arithmetic coding) - Differential progressive DCT" },
174         { MARKER_SOF15, "Start of Frame (differential, arithmetic coding) - Differential lossless (sequential)" },
175         { MARKER_RST0,  "Restart interval termination - Restart with modulo 8 count 0" },
176         { MARKER_RST1,  "Restart interval termination - Restart with modulo 8 count 1" },
177         { MARKER_RST2,  "Restart interval termination - Restart with modulo 8 count 2" },
178         { MARKER_RST3,  "Restart interval termination - Restart with modulo 8 count 3" },
179         { MARKER_RST4,  "Restart interval termination - Restart with modulo 8 count 4" },
180         { MARKER_RST5,  "Restart interval termination - Restart with modulo 8 count 5" },
181         { MARKER_RST6,  "Restart interval termination - Restart with modulo 8 count 6" },
182         { MARKER_RST7,  "Restart interval termination - Restart with modulo 8 count 7" },
183         { MARKER_SOI,   "Start of Image" },
184         { MARKER_EOI,   "End of Image" },
185         { MARKER_SOS,   "Start of Scan" },
186         { MARKER_DQT,   "Define quantization table(s)" },
187         { MARKER_DNL,   "Define number of lines" },
188         { MARKER_DRI,   "Define restart interval" },
189         { MARKER_DHP,   "Define hierarchical progression" },
190         { MARKER_EXP,   "Expand reference component(s)" },
191         { MARKER_APP0,  "Reserved for application segments - 0" },
192         { MARKER_APP1,  "Reserved for application segments - 1" },
193         { MARKER_APP2,  "Reserved for application segments - 2" },
194         { MARKER_APP3,  "Reserved for application segments - 3" },
195         { MARKER_APP4,  "Reserved for application segments - 4" },
196         { MARKER_APP5,  "Reserved for application segments - 5" },
197         { MARKER_APP6,  "Reserved for application segments - 6" },
198         { MARKER_APP7,  "Reserved for application segments - 7" },
199         { MARKER_APP8,  "Reserved for application segments - 8" },
200         { MARKER_APP9,  "Reserved for application segments - 9" },
201         { MARKER_APP10, "Reserved for application segments - 10" },
202         { MARKER_APP11, "Reserved for application segments - 11" },
203         { MARKER_APP12, "Reserved for application segments - 12" },
204         { MARKER_APP13, "Reserved for application segments - 13" },
205         { MARKER_APP14, "Reserved for application segments - 14" },
206         { MARKER_APP15, "Reserved for application segments - 15" },
207         { MARKER_JPG0,  "Reserved for JPEG extensions - 0" },
208         { MARKER_JPG1,  "Reserved for JPEG extensions - 1" },
209         { MARKER_JPG2,  "Reserved for JPEG extensions - 2" },
210         { MARKER_JPG3,  "Reserved for JPEG extensions - 3" },
211         { MARKER_JPG4,  "Reserved for JPEG extensions - 4" },
212         { MARKER_JPG5,  "Reserved for JPEG extensions - 5" },
213         { MARKER_JPG6,  "Reserved for JPEG extensions - 6" },
214         { MARKER_JPG7,  "Reserved for JPEG extensions - 7" },
215         { MARKER_JPG8,  "Reserved for JPEG extensions - 8" },
216         { MARKER_JPG9,  "Reserved for JPEG extensions - 9" },
217         { MARKER_JPG10, "Reserved for JPEG extensions - 10" },
218         { MARKER_JPG11, "Reserved for JPEG extensions - 11" },
219         { MARKER_JPG12, "Reserved for JPEG extensions - 12" },
220         { MARKER_JPG13, "Reserved for JPEG extensions - 13" },
221         { MARKER_COM,   "Comment" },
222         { 0x00, NULL }
223 };
224
225 static const value_string vals_units[] = {
226         { 0, "No units; Xdensity and Ydensity specify the pixel aspect ratio" },
227         { 1, "Dots per inch" },
228         { 2, "Dots per centimeter" },
229         { 0x00, NULL }
230 };
231
232 static const value_string vals_extension_code[] = {
233         { 0x10, "Thumbnail encoded using JPEG" },
234         { 0x11, "Thumbnail encoded using 1 byte (8 bits) per pixel" },
235         { 0x13, "Thumbnail encoded using 3 bytes (24 bits) per pixel" },
236         { 0x00, NULL }
237 };
238
239 static const value_string vals_exif_tags[] = {
240         /*
241          * Tags related to image data structure:
242          */
243         { 0x0100, "ImageWidth" },
244         { 0x0101, "ImageLength" },
245         { 0x0102, "BitsPerSample" },
246         { 0x0103, "Compression" },
247         { 0x0106, "PhotometricInterpretation" },
248         { 0x0112, "Orientation" },
249         { 0x0115, "SamplesPerPixel" },
250         { 0x011C, "PlanarConfiguration" },
251         { 0x0212, "YCbCrSubSampling" },
252         { 0x0213, "YCbCrPositioning" },
253         { 0x011A, "XResolution" },
254         { 0x011B, "YResolution" },
255         { 0x0128, "ResolutionUnit" },
256         /*
257          * Tags relating to recording offset:
258          */
259         { 0x0111, "StripOffsets" },
260         { 0x0116, "RowsPerStrip" },
261         { 0x0117, "StripByteCounts" },
262         { 0x0201, "JPEGInterchangeFormat" },
263         { 0x0202, "JPEGInterchangeFormatLength" },
264         /*
265          * Tags relating to image data characteristics:
266          */
267         { 0x012D, "TransferFunction" },
268         { 0x013E, "WhitePoint" },
269         { 0x013F, "PrimaryChromaticities" },
270         { 0x0211, "YCbCrCoefficients" },
271         { 0x0214, "ReferenceBlackWhite" },
272         /*
273          * Other tags:
274          */
275         { 0x0132, "DateTime" },
276         { 0x010E, "ImageDescription" },
277         { 0x010F, "Make" },
278         { 0x0110, "Model" },
279         { 0x0131, "Software" },
280         { 0x013B, "Artist" },
281         { 0x8296, "Copyright" },
282         /*
283          * Exif-specific IFD:
284          */
285         { 0x8769, "Exif IFD Pointer"},
286         { 0x8825, "GPS IFD Pointer"},
287         { 0xA005, "Interoperability IFD Pointer"},
288
289         { 0x0000, NULL }
290 };
291
292 static const value_string vals_exif_types[] = {
293         { 0x0001, "BYTE" },
294         { 0x0002, "ASCII" },
295         { 0x0003, "SHORT" },
296         { 0x0004, "LONG" },
297         { 0x0005, "RATIONAL" },
298         /* 0x0006 */
299         { 0x0007, "UNDEFINED" },
300         /* 0x0008 */
301         { 0x0009, "SLONG" },
302         { 0x000A, "SRATIONAL" },
303
304         { 0x0000, NULL }
305 };
306
307 /* Initialize the protocol and registered fields */
308 static int proto_jfif = -1;
309
310 /* Marker */
311 static gint hf_marker = -1;
312 /* Marker segment */
313 static gint hf_marker_segment = -1;
314 static gint hf_len = -1;
315 /* MARKER_APP0 */
316 static gint hf_identifier = -1;
317 /* MARKER_APP0 - JFIF */
318 static gint hf_version = -1;
319 static gint hf_version_major = -1;
320 static gint hf_version_minor = -1;
321 static gint hf_units = -1;
322 static gint hf_xdensity = -1;
323 static gint hf_ydensity = -1;
324 static gint hf_xthumbnail = -1;
325 static gint hf_ythumbnail = -1;
326 static gint hf_rgb = -1;
327 /* MARKER_APP0 - JFXX */
328 static gint hf_extension_code = -1;
329 /* start of Frame */
330 static gint hf_sof_header = -1;
331 static gint hf_sof_precision = -1;
332 static gint hf_sof_lines = -1;
333 static gint hf_sof_samples_per_line = -1;
334 static gint hf_sof_nf = -1;
335 static gint hf_sof_c_i = -1;
336 static gint hf_sof_h_i = -1;
337 static gint hf_sof_v_i = -1;
338 static gint hf_sof_tq_i = -1;
339
340 /* Start of Scan */
341 static gint hf_sos_header = -1;
342 static gint hf_sos_ns = -1;
343 static gint hf_sos_cs_j = -1;
344 static gint hf_sos_td_j = -1;
345 static gint hf_sos_ta_j = -1;
346 static gint hf_sos_ss = -1;
347 static gint hf_sos_se = -1;
348 static gint hf_sos_ah = -1;
349 static gint hf_sos_al = -1;
350
351 /* Initialize the subtree pointers */
352 static gint ett_jfif = -1;
353 static gint ett_marker_segment = -1;
354 static gint ett_details = -1;
355
356
357 /****************** JFIF protocol dissection functions ******************/
358
359 #define ErrorInvalidJFIF "This is not a valid JFIF (JPEG) object"
360
361
362 /*
363  * Process a marker segment (with length).
364  */
365 static void
366 process_marker_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len,
367                 guint16 marker, const char *marker_name)
368 {
369         proto_item *ti = NULL;
370         proto_tree *subtree = NULL;
371
372         if (! tree)
373                 return;
374
375         ti = proto_tree_add_item(tree, hf_marker_segment,
376                         tvb, 0, -1, FALSE);
377         subtree = proto_item_add_subtree(ti, ett_marker_segment);
378
379         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
380         proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
381
382         proto_tree_add_item(subtree, hf_len, tvb, 2, 2, FALSE);
383
384         proto_tree_add_text(subtree, tvb, 4, -1,
385                         "Remaining segment data (%u bytes)", len - 2);
386 }
387
388 /*
389  * Process a Start of Frame header (with length).
390  */
391 static void
392 process_sof_header(proto_tree *tree, tvbuff_t *tvb, guint32 len _U_,
393                 guint16 marker, const char *marker_name)
394 {
395         proto_item *ti = NULL;
396         proto_tree *subtree = NULL;
397
398         if (! tree)
399                 return;
400
401         ti = proto_tree_add_item(tree, hf_sof_header,
402                         tvb, 0, -1, FALSE);
403         subtree = proto_item_add_subtree(ti, ett_marker_segment);
404
405         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
406         proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
407
408         proto_tree_add_item(subtree, hf_len, tvb, 2, 2, FALSE);
409
410         proto_tree_add_item(subtree, hf_sof_precision, tvb, 4, 1, FALSE);
411
412         proto_tree_add_item(subtree, hf_sof_lines, tvb, 5, 2, FALSE);
413
414         proto_tree_add_item(subtree, hf_sof_samples_per_line, tvb, 7, 2, FALSE);
415
416         proto_tree_add_item(subtree, hf_sof_nf, tvb, 9, 1, FALSE);
417         {
418                 guint8 count = tvb_get_guint8(tvb, 9);
419                 guint32 offset = 10;
420                 while (count > 0) {
421                         proto_tree_add_item(subtree, hf_sof_c_i, tvb, offset++, 1, FALSE);
422                         proto_tree_add_item(subtree, hf_sof_h_i, tvb, offset, 1, FALSE);
423                         proto_tree_add_item(subtree, hf_sof_v_i, tvb, offset++, 1, FALSE);
424                         proto_tree_add_item(subtree, hf_sof_tq_i, tvb, offset++, 1, FALSE);
425                         count--;
426                 }
427         }
428 }
429
430 /*
431  * Process a Start of Segment header (with length).
432  */
433 static void
434 process_sos_header(proto_tree *tree, tvbuff_t *tvb, guint32 len _U_,
435                 guint16 marker, const char *marker_name)
436 {
437         proto_item *ti = NULL;
438         proto_tree *subtree = NULL;
439         guint32 offset;
440
441         if (! tree)
442                 return;
443
444         ti = proto_tree_add_item(tree, hf_sos_header,
445                         tvb, 0, -1, FALSE);
446         subtree = proto_item_add_subtree(ti, ett_marker_segment);
447
448         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
449         proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
450
451         proto_tree_add_item(subtree, hf_len, tvb, 2, 2, FALSE);
452
453         proto_tree_add_item(subtree, hf_sos_ns, tvb, 4, 1, FALSE);
454         {
455                 guint8 count = tvb_get_guint8(tvb, 4);
456                 offset = 5;
457                 while (count > 0) {
458                         proto_tree_add_item(subtree, hf_sos_cs_j, tvb, offset++, 1, FALSE);
459                         proto_tree_add_item(subtree, hf_sos_td_j, tvb, offset, 1, FALSE);
460                         proto_tree_add_item(subtree, hf_sos_ta_j, tvb, offset++, 1, FALSE);
461                         count--;
462                 }
463         }
464
465         proto_tree_add_item(subtree, hf_sos_ss, tvb, offset++, 1, FALSE);
466         proto_tree_add_item(subtree, hf_sos_se, tvb, offset++, 1, FALSE);
467
468         proto_tree_add_item(subtree, hf_sos_ah, tvb, offset, 1, FALSE);
469         proto_tree_add_item(subtree, hf_sos_al, tvb, offset++, 1, FALSE);
470 }
471
472 /* Process an APP0 block.
473  *
474  * XXX - This code only works on US-ASCII systems!!!
475  */
476 static void
477 process_app0_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len,
478                 guint16 marker, const char *marker_name)
479 {
480         proto_item *ti = NULL;
481         proto_tree *subtree = NULL;
482         proto_tree *subtree_details = NULL;
483         guint32 offset;
484         char *str;
485         gint str_size;
486
487         if (!tree)
488                 return;
489
490         ti = proto_tree_add_item(tree, hf_marker_segment,
491                         tvb, 0, -1, FALSE);
492         subtree = proto_item_add_subtree(ti, ett_marker_segment);
493
494         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
495         proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
496
497         proto_tree_add_item(subtree, hf_len, tvb, 2, 2, FALSE);
498
499         str = tvb_get_ephemeral_stringz(tvb, 4, &str_size);
500         ti = proto_tree_add_item(subtree, hf_identifier, tvb, 4, str_size, FALSE);
501         if (strcmp(str, "JFIF") == 0) {
502                 /* Version */
503                 ti = proto_tree_add_none_format(subtree, hf_version,
504                                 tvb, 9, 2, "Version: %u.%u",
505                                 tvb_get_guint8(tvb, 9),
506                                 tvb_get_guint8(tvb, 10));
507                 subtree_details = proto_item_add_subtree(ti, ett_details);
508                 proto_tree_add_item(subtree_details, hf_version_major,
509                                 tvb, 9, 1, FALSE);
510                 proto_tree_add_item(subtree_details, hf_version_minor,
511                                 tvb, 10, 1, FALSE);
512
513                 proto_tree_add_item(subtree, hf_units,
514                                 tvb, 11, 1, FALSE);
515
516                 /* Aspect ratio */
517                 proto_tree_add_item(subtree, hf_xdensity,
518                                 tvb, 12, 2, FALSE);
519                 proto_tree_add_item(subtree, hf_ydensity,
520                                 tvb, 14, 2, FALSE);
521
522                 /* Thumbnail */
523                 proto_tree_add_item(subtree, hf_xthumbnail,
524                                 tvb, 16, 1, FALSE);
525                 proto_tree_add_item(subtree, hf_ythumbnail,
526                                 tvb, 17, 1, FALSE);
527                 {
528                         guint16 x = tvb_get_guint8(tvb, 16);
529                         guint16 y = tvb_get_guint8(tvb, 17);
530                         if (x || y) {
531                                 proto_tree_add_item(subtree, hf_rgb,
532                                                 tvb, 18, 3 * (x * y), FALSE);
533                                 offset = 18 + (3 * (x * y));
534                         } else {
535                                 offset = 18;
536                         }
537                 }
538         } else if (strcmp(str, "JFXX") == 0) {
539                 proto_tree_add_item(subtree, hf_extension_code,
540                                 tvb, 9, 1, FALSE);
541                 {
542                         guint8 code = tvb_get_guint8(tvb, 9);
543                         switch (code) {
544                                 case 0x10: /* Thumbnail coded using JPEG */
545                                         break;
546                                 case 0x11: /* thumbnail stored using 1 byte per pixel */
547                                         break;
548                                 case 0x13: /* thumbnail stored using 3 bytes per pixel */
549                                         break;
550                                 default: /* Error */
551                                         break;
552                         }
553                 }
554         } else { /* Unknown */
555                 proto_item_append_text(ti, " (unknown identifier)");
556                 offset = 4 + str_size;
557
558                 proto_tree_add_text(subtree, tvb, offset, -1,
559                                 "Remaining segment data (%u bytes)", len - 2 - str_size);
560         }
561         return;
562 }
563
564 /* Process an APP1 block.
565  *
566  * XXX - This code only works on US-ASCII systems!!!
567  */
568 static void
569 process_app1_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len,
570                 guint16 marker, const char *marker_name)
571 {
572         proto_item *ti = NULL;
573         proto_tree *subtree = NULL;
574         char *str;
575         gint str_size;
576         int offset = 0;
577         int tiff_start;
578
579         if (!tree)
580                 return;
581
582         ti = proto_tree_add_item(tree, hf_marker_segment,
583                         tvb, 0, -1, FALSE);
584         subtree = proto_item_add_subtree(ti, ett_marker_segment);
585
586         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
587         proto_tree_add_item(subtree, hf_marker, tvb, offset, 2, FALSE);
588         offset += 2;
589
590         proto_tree_add_item(subtree, hf_len, tvb, offset, 2, FALSE);
591         offset += 2;
592
593         str = tvb_get_ephemeral_stringz(tvb, offset, &str_size);
594         ti = proto_tree_add_item(subtree, hf_identifier, tvb, offset, str_size, FALSE);
595         offset += str_size;
596         if (strcmp(str, "Exif") == 0) {
597                 /*
598                  * Endianness
599                  */
600                 gboolean is_little_endian;
601                 guint16 val_16;
602                 guint32 val_32;
603                 guint16 num_fields;
604
605                 offset++; /* Skip a byte supposed to be 0x00 */
606
607                 tiff_start = offset;
608                 val_16 = tvb_get_ntohs(tvb, offset);
609                 if (val_16 == 0x4949) {
610                         is_little_endian = TRUE;
611                         proto_tree_add_text(subtree, tvb, offset, 2, "Endianness: little endian");
612                 } else if (val_16 == 0x4D4D) {
613                         is_little_endian = FALSE;
614                         proto_tree_add_text(subtree, tvb, offset, 2, "Endianness: big endian");
615                 } else {
616                         /* Error: invalid endianness encoding */
617                         proto_tree_add_text(subtree, tvb, offset, 2,
618                                         "Incorrect endianness encoding - skipping the remainder of this application marker");
619                         return;
620                 }
621                 offset += 2;
622                 /*
623                  * Fixed value 42 = 0x002a
624                  */
625                 offset += 2;
626                 /*
627                  * Offset to IFD
628                  */
629                 if (is_little_endian) {
630                         val_32 = tvb_get_letohl(tvb, offset);
631                 } else {
632                         val_32 = tvb_get_ntohl(tvb, offset);
633                 }
634                 /*
635                  * Check for a bogus val_32 value.
636                  * XXX - bogus value message should also deal with a
637                  * value that's too large and causes an overflow.
638                  * Or should it just check against the segment length,
639                  * which is 16 bits?
640                  */
641                 if (val_32 + tiff_start < (guint32)offset + 4) {
642                         proto_tree_add_text(subtree, tvb, offset, 4,
643                             "Start offset of IFD starting from the TIFF header start: %u bytes (bogus, should be >= %u",
644                             val_32, offset + 4 - tiff_start);
645                         return;
646                 }
647                 proto_tree_add_text(subtree, tvb, offset, 4,
648                     "Start offset of IFD starting from the TIFF header start: %u bytes",
649                     val_32);
650                 offset += 4;
651                 /*
652                  * Skip the following portion
653                  */
654                 if (val_32 + tiff_start > (guint32)offset) {
655                         proto_tree_add_text(subtree, tvb, offset, val_32 + tiff_start - offset,
656                             "Skipped data between end of TIFF header and start of IFD (%u bytes)",
657                             val_32 + tiff_start - offset);
658                 }
659                 for (;;) {
660                         offset = val_32 + tiff_start;
661                         /*
662                          * Process the IFD
663                          */
664                         if (is_little_endian) {
665                                 num_fields = tvb_get_letohs(tvb, offset);
666                         } else {
667                                 num_fields = tvb_get_ntohs(tvb, offset);
668                         }
669                         proto_tree_add_text(subtree, tvb, offset, 2, "Number of fields in this IFD: %u", num_fields);
670                         offset += 2;
671                         while (num_fields-- > 0) {
672                                 guint16 tag, type;
673                                 guint32 count, off;
674
675                                 if (is_little_endian) {
676                                         tag = tvb_get_letohs(tvb, offset);
677                                         type = tvb_get_letohs(tvb, offset + 2);
678                                         count = tvb_get_letohl(tvb, offset + 4);
679                                         off = tvb_get_letohl(tvb, offset + 8);
680                                 } else {
681                                         tag = tvb_get_ntohs(tvb, offset);
682                                         type = tvb_get_ntohs(tvb, offset + 2);
683                                         count = tvb_get_ntohl(tvb, offset + 4);
684                                         off = tvb_get_ntohl(tvb, offset + 8);
685                                 }
686                                 /* TODO - refine this */
687                                 proto_tree_add_text(subtree, tvb, offset, 2,
688                                     "Exif Tag: 0x%04X (%s), Type: %u (%s), Count: %u, "
689                                     "Value offset from start of TIFF header: %u",
690                                     tag, val_to_str(tag, vals_exif_tags, "Unknown Exif tag"),
691                                     type, val_to_str(type, vals_exif_types, "Unknown Exif type"),
692                                     count, off);
693                                 offset += 12;
694                         }
695                         /*
696                          * Offset to the next IFD
697                          */
698                         if (is_little_endian) {
699                                 val_32 = tvb_get_letohl(tvb, offset);
700                         } else {
701                                 val_32 = tvb_get_ntohl(tvb, offset);
702                         }
703                         if (val_32 != 0 &&
704                             val_32 + tiff_start < (guint32)offset + 4) {
705                                 proto_tree_add_text(subtree, tvb, offset, 4,
706                                     "Offset to next IFD from start of TIFF header: %u bytes (bogus, should be >= %u)",
707                                     val_32, offset + 4 - tiff_start);
708                                 return;
709                         }
710                         proto_tree_add_text(subtree, tvb, offset, 4,
711                             "Offset to next IFD from start of TIFF header: %u bytes",
712                             val_32);
713                         offset += 4;
714                         if (val_32 == 0)
715                                 break;
716                 }
717         } else {
718                 proto_tree_add_text(subtree, tvb, offset, -1,
719                                 "Remaining segment data (%u bytes)", len - 2 - str_size);
720                 proto_item_append_text(ti, " (Unknown identifier)");
721         }
722 }
723
724 /* Process an APP2 block.
725  *
726  * XXX - This code only works on US-ASCII systems!!!
727  */
728 static void
729 process_app2_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len,
730                 guint16 marker, const char *marker_name)
731 {
732         proto_item *ti = NULL;
733         proto_tree *subtree = NULL;
734         char *str;
735         gint str_size;
736
737         if (!tree)
738                 return;
739
740         ti = proto_tree_add_item(tree, hf_marker_segment,
741                         tvb, 0, -1, FALSE);
742         subtree = proto_item_add_subtree(ti, ett_marker_segment);
743
744         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
745         proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
746
747         proto_tree_add_item(subtree, hf_len, tvb, 2, 2, FALSE);
748
749         str = tvb_get_ephemeral_stringz(tvb, 4, &str_size);
750         ti = proto_tree_add_item(subtree, hf_identifier, tvb, 4, str_size, FALSE);
751         if (strcmp(str, "FPXR") == 0) {
752                 proto_tree_add_text(tree, tvb, 0, -1, "Exif FlashPix APP2 application marker");
753         } else {
754                 proto_tree_add_text(subtree, tvb, 4 + str_size, -1,
755                                 "Remaining segment data (%u bytes)", len - 2 - str_size);
756                 proto_item_append_text(ti, " (Unknown identifier)");
757         }
758 }
759
760 static gint
761 dissect_jfif(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
762 {
763         proto_tree *subtree = NULL;
764         proto_item *ti = NULL;
765         guint tvb_len = tvb_reported_length(tvb);
766         guint32 offset = 0;
767
768         /* check if we have a full JFIF in tvb */
769         if (tvb_len < 20)
770                 return 0;
771         if (tvb_get_ntohs(tvb, 0) != MARKER_SOI)
772                 return 0;
773         if (tvb_get_ntohs(tvb, tvb_len-2) != MARKER_EOI)
774                 return 0;
775
776         /* Add summary to INFO column if it is enabled */
777         if (check_col(pinfo->cinfo, COL_INFO))
778                 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(JPEG JFIF image)");
779
780         if (tree) {
781                 ti = proto_tree_add_item(tree, proto_jfif,
782                                 tvb, 0, -1, FALSE);
783                 subtree = proto_item_add_subtree(ti, ett_jfif);
784                 proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
785         }
786
787         offset = 2;             /* skip MARKER_SOI */
788
789         /*
790          * Process the remaining markers and marker segments
791          */
792         while (offset < tvb_len) {
793                 const char *str;
794                 const guint16 marker = tvb_get_ntohs(tvb, offset);
795                 str = match_strval(marker, vals_marker);
796                 if (str) { /* Known marker */
797                         if (marker_has_length(marker)) { /* Marker segment */
798                                 /* Length of marker segment = 2 + len */
799                                 const guint16 len = tvb_get_ntohs(tvb, offset + 2);
800                                 tvbuff_t *tmp_tvb = tvb_new_subset(tvb, offset, 2 + len, 2 + len);
801                                 switch (marker) {
802                                         case MARKER_APP0:
803                                                 process_app0_segment(subtree, tmp_tvb, len, marker, str);
804                                                 break;
805                                         case MARKER_APP1:
806                                                 process_app1_segment(subtree, tmp_tvb, len, marker, str);
807                                                 break;
808                                         case MARKER_APP2:
809                                                 process_app2_segment(subtree, tmp_tvb, len, marker, str);
810                                                 break;
811                                         case MARKER_SOF0:
812                                         case MARKER_SOF1:
813                                         case MARKER_SOF2:
814                                         case MARKER_SOF3:
815                                         case MARKER_SOF5:
816                                         case MARKER_SOF6:
817                                         case MARKER_SOF7:
818                                         case MARKER_SOF8:
819                                         case MARKER_SOF9:
820                                         case MARKER_SOF10:
821                                         case MARKER_SOF11:
822                                         case MARKER_SOF13:
823                                         case MARKER_SOF14:
824                                         case MARKER_SOF15:
825                                                 process_sof_header(subtree, tmp_tvb, len, marker, str);
826                                                 break;
827                                         case MARKER_SOS:
828                                                 process_sos_header(subtree, tmp_tvb, len, marker, str);
829                                                 /*
830                                                  * TODO - dissect a scan; the scan data is encoded.
831                                                  */
832                                                 proto_tree_add_text(subtree, tvb, offset + 2 + len, -1,
833                                                                 "JFIF dissection stops here (dissection of a scan is not yet implemented)");
834                                                 return tvb_len;
835                                                 break;
836                                         default:
837                                                 process_marker_segment(subtree, tmp_tvb, len, marker, str);
838                                                 break;
839                                 }
840                                 offset += 2 + len;
841                         } else { /* Marker but no segment */
842                                 /* Length = 2 */
843                                 proto_tree_add_item(subtree, hf_marker,
844                                                 tvb, offset, 2, FALSE);
845                                 offset += 2;
846                         }
847                 } else { /* Reserved! */
848                         ti = proto_tree_add_item(subtree, hf_marker,
849                                         tvb, offset, 2, FALSE);
850                         proto_item_append_text(ti, " (Reserved)");
851                         return tvb_len;
852                 }
853         }
854
855         return offset;
856 }
857
858 static gboolean
859 dissect_jfif_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
860 {
861         return dissect_jfif(tvb, pinfo, tree) > 0;
862 }
863
864 /****************** Register the protocol with Wireshark ******************/
865
866
867 /* This format is required because a script is used to build the C function
868  * that calls the protocol registration. */
869
870 void
871 proto_register_jfif(void)
872 {
873         /*
874          * Setup list of header fields.
875          */
876         static hf_register_info hf[] = {
877                 /* Marker */
878                 { &hf_marker,
879                         {       "Marker",
880                                 IMG_JFIF ".marker",
881                                 FT_UINT8, BASE_HEX, VALS(vals_marker), 0x00,
882                                 "JFIF Marker",
883                                 HFILL
884                         }
885                 },
886                 /* Marker segment */
887                 { &hf_marker_segment,
888                         {       "Marker segment",
889                                 IMG_JFIF ".marker_segment",
890                                 FT_NONE, BASE_NONE, NULL, 0x00,
891                                 NULL,
892                                 HFILL
893                         }
894                 },
895                 { &hf_len,
896                         {       "Length",
897                                 IMG_JFIF ".length",
898                                 FT_UINT16, BASE_DEC, 0, 0x00,
899                                 "Length of segment (including length field)",
900                                 HFILL
901                         }
902                 },
903                 /* MARKER_APP0 */
904                 { &hf_identifier,
905                         {       "Identifier",
906                                 IMG_JFIF ".identifier",
907                                 FT_STRINGZ, BASE_NONE, NULL, 0x00,
908                                 "Identifier of the segment",
909                                 HFILL
910                         }
911                 },
912                 /* MARKER_APP0 - JFIF */
913                 { &hf_version,
914                         {       "Version",
915                                 IMG_JFIF ".version",
916                                 FT_NONE, BASE_NONE, NULL, 0x00,
917                                 "JFIF Version",
918                                 HFILL
919                         }
920                 },
921                 { &hf_version_major,
922                         {       "Major Version",
923                                 IMG_JFIF ".version.major",
924                                 FT_UINT8, BASE_DEC, NULL, 0x00,
925                                 "JFIF Major Version",
926                                 HFILL
927                         }
928                 },
929                 { &hf_version_minor,
930                         {       "Minor Version",
931                                 IMG_JFIF ".version.minor",
932                                 FT_UINT8, BASE_DEC, NULL, 0x00,
933                                 "JFIF Minor Version",
934                                 HFILL
935                         }
936                 },
937                 { &hf_units,
938                         {       "Units",
939                                 IMG_JFIF ".units",
940                                 FT_UINT8, BASE_DEC, VALS(vals_units), 0x00,
941                                 "Units used in this segment",
942                                 HFILL
943                         }
944                 },
945                 { &hf_xdensity,
946                         {       "Xdensity",
947                                 IMG_JFIF ".Xdensity",
948                                 FT_UINT16, BASE_DEC, NULL, 0x00,
949                                 "Horizontal pixel density",
950                                 HFILL
951                         }
952                 },
953                 { &hf_ydensity,
954                         {       "Ydensity",
955                                 IMG_JFIF ".Ydensity",
956                                 FT_UINT16, BASE_DEC, NULL, 0x00,
957                                 "Vertical pixel density",
958                                 HFILL
959                         }
960                 },
961                 { &hf_xthumbnail,
962                         {       "Xthumbnail",
963                                 IMG_JFIF ".Xthumbnail",
964                                 FT_UINT16, BASE_DEC, NULL, 0x00,
965                                 "Thumbnail horizontal pixel count",
966                                 HFILL
967                         }
968                 },
969                 { &hf_ythumbnail,
970                         {       "Ythumbnail",
971                                 IMG_JFIF ".Ythumbnail",
972                                 FT_UINT16, BASE_DEC, NULL, 0x00,
973                                 "Thumbnail vertical pixel count",
974                                 HFILL
975                         }
976                 },
977                 { &hf_rgb,
978                         {       "RGB values of thumbnail pixels",
979                                 IMG_JFIF ".RGB",
980                                 FT_BYTES, BASE_NONE, NULL, 0x00,
981                                 "RGB values of the thumbnail pixels (24 bit per pixel, Xthumbnail x Ythumbnail pixels)",
982                                 HFILL
983                         }
984                 },
985                 /* MARKER_APP0 - JFXX */
986                 { &hf_extension_code,
987                         {       "Extension code",
988                                 IMG_JFIF ".extension.code",
989                                 FT_UINT8, BASE_HEX, VALS(vals_extension_code), 0x00,
990                                 "JFXX extension code for thumbnail encoding",
991                                 HFILL
992                         }
993                 },
994                 /* Header: Start of Frame (MARKER_SOF) */
995                 { &hf_sof_header,
996                         {       "Start of Frame header",
997                                 IMG_JFIF ".sof",
998                                 FT_NONE, BASE_NONE, NULL, 0x00,
999                                 NULL,
1000                                 HFILL
1001                         }
1002                 },
1003                 { &hf_sof_precision,
1004                         {       "Sample Precision (bits)",
1005                                 IMG_JFIF ".sof.precision",
1006                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1007                                 "Specifies the precision in bits for the samples of the components in the frame.",
1008                                 HFILL
1009                         }
1010                 },
1011                 { &hf_sof_lines,
1012                         {       "Lines",
1013                                 IMG_JFIF ".sof.lines",
1014                                 FT_UINT16, BASE_DEC, NULL, 0x00,
1015                                 "Specifies the maximum number of lines in the source image.",
1016                                 HFILL
1017                         }
1018                 },
1019                 { &hf_sof_samples_per_line,
1020                         {       "Samples per line",
1021                                 IMG_JFIF ".sof.samples_per_line",
1022                                 FT_UINT16, BASE_DEC, NULL, 0x00,
1023                                 "Specifies the maximum number of samples per line in the source image.",
1024                                 HFILL
1025                         }
1026                 },
1027                 { &hf_sof_nf,
1028                         {       "Number of image components in frame",
1029                                 IMG_JFIF ".sof.nf",
1030                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1031                                 "Specifies the number of source image components in the frame.",
1032                                 HFILL
1033                         }
1034                 },
1035                 { &hf_sof_c_i,
1036                         {       "Component identifier",
1037                                 IMG_JFIF ".sof.c_i",
1038                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1039                                 "Assigns a unique label to the ith component in the sequence of frame component specification parameters.",
1040                                 HFILL
1041                         }
1042                 },
1043                 { &hf_sof_h_i,
1044                         {       "Horizontal sampling factor",
1045                                 IMG_JFIF ".sof.h_i",
1046                                 FT_UINT8, BASE_DEC, NULL, 0xF0,
1047                                 "Specifies the relationship between the component horizontal dimension and maximum image dimension X.",
1048                                 HFILL
1049                         }
1050                 },
1051                 { &hf_sof_v_i,
1052                         {       "Vertical sampling factor",
1053                                 IMG_JFIF ".sof.v_i",
1054                                 FT_UINT8, BASE_DEC, NULL, 0x0F,
1055                                 "Specifies the relationship between the component vertical dimension and maximum image dimension Y.",
1056                                 HFILL
1057                         }
1058                 },
1059                 { &hf_sof_tq_i,
1060                         {       "Quantization table destination selector",
1061                                 IMG_JFIF ".sof.tq_i",
1062                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1063                                 "Specifies one of four possible quantization table destinations from which the quantization table to use for dequantization of DCT coefficients of component Ci is retrieved.",
1064                                 HFILL
1065                         }
1066                 },
1067
1068                 /* Header: Start of Segment (MARKER_SOS) */
1069                 { &hf_sos_header,
1070                         {       "Start of Segment header",
1071                                 IMG_JFIF ".header.sos",
1072                                 FT_NONE, BASE_NONE, NULL, 0x00,
1073                                 NULL,
1074                                 HFILL
1075                         }
1076                 },
1077                 { &hf_sos_ns,
1078                         {       "Number of image components in scan",
1079                                 IMG_JFIF ".sos.ns",
1080                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1081                                 "Specifies the number of source image components in the scan.",
1082                                 HFILL
1083                         }
1084                 },
1085                 { &hf_sos_cs_j,
1086                         {       "Scan component selector",
1087                                 IMG_JFIF ".sos.component_selector",
1088                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1089                                 "Selects which of the Nf image components specified in the frame parameters shall be the jth component in the scan.",
1090                                 HFILL
1091                         }
1092                 },
1093                 { &hf_sos_td_j,
1094                         {       "DC entropy coding table destination selector",
1095                                 IMG_JFIF ".sos.dc_entropy_selector",
1096                                 FT_UINT8, BASE_DEC, NULL, 0xF0,
1097                                 "Specifies one of four possible DC entropy coding table destinations from which the entropy table needed for decoding of the DC coefficients of component Csj is retrieved.",
1098                                 HFILL
1099                         }
1100                 },
1101                 { &hf_sos_ta_j,
1102                         {       "AC entropy coding table destination selector",
1103                                 IMG_JFIF ".sos.ac_entropy_selector",
1104                                 FT_UINT8, BASE_DEC, NULL, 0x0F,
1105                                 "Specifies one of four possible AC entropy coding table destinations from which the entropy table needed for decoding of the AC coefficients of component Csj is retrieved.",
1106                                 HFILL
1107                         }
1108                 },
1109                 { &hf_sos_ss,
1110                         {       "Start of spectral or predictor selection",
1111                                 IMG_JFIF ".sos.ss",
1112                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1113                                 "In the DCT modes of operation, this parameter specifies the first DCT coefficient in each block in zig-zag order which shall be coded in the scan. This parameter shall be set to zero for the sequential DCT processes. In the lossless mode of operations this parameter is used to select the predictor.",
1114                                 HFILL
1115                         }
1116                 },
1117                 { &hf_sos_se,
1118                         {       "End of spectral selection",
1119                                 IMG_JFIF ".sos.se",
1120                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1121                                 "Specifies the last DCT coefficient in each block in zig-zag order which shall be coded in the scan. This parameter shall be set to 63 for the sequential DCT processes. In the lossless mode of operations this parameter has no meaning. It shall be set to zero.",
1122                                 HFILL
1123                         }
1124                 },
1125                 { &hf_sos_ah,
1126                         {       "Successive approximation bit position high",
1127                                 IMG_JFIF ".sos.ah",
1128                                 FT_UINT8, BASE_DEC, NULL, 0xF0,
1129                                 "This parameter specifies the point transform used in the preceding scan (i.e. successive approximation bit position low in the preceding scan) for the band of coefficients specified by Ss and Se. This parameter shall be set to zero for the first scan of each band of coefficients. In the lossless mode of operations this parameter has no meaning. It shall be set to zero.",
1130                                 HFILL
1131                         }
1132                 },
1133                 { &hf_sos_al,
1134                         {       "Successive approximation bit position low or point transform",
1135                                 IMG_JFIF ".sos.al",
1136                                 FT_UINT8, BASE_DEC, NULL, 0x0F,
1137                                 "In the DCT modes of operation this parameter specifies the point transform, i.e. bit position low, used before coding the band of coefficients specified by Ss and Se. This parameter shall be set to zero for the sequential DCT processes. In the lossless mode of operations, this parameter specifies the point transform, Pt.",
1138                                 HFILL
1139                         }
1140                 },
1141         };
1142
1143         /* Setup protocol subtree array */
1144         static gint *ett[] = {
1145                 &ett_jfif,
1146                 &ett_marker_segment,
1147                 &ett_details,
1148         };
1149
1150         /* Register the protocol name and description */
1151         proto_jfif = proto_register_protocol(
1152                         "JPEG File Interchange Format",
1153                         "JFIF (JPEG) image",
1154                         IMG_JFIF
1155         );
1156
1157         /* Required function calls to register the header fields
1158          * and subtrees used */
1159         proto_register_field_array(proto_jfif, hf, array_length(hf));
1160         proto_register_subtree_array(ett, array_length(ett));
1161
1162         new_register_dissector(IMG_JFIF, dissect_jfif, proto_jfif);
1163 }
1164
1165
1166 void
1167 proto_reg_handoff_jfif(void)
1168 {
1169         dissector_handle_t jfif_handle = find_dissector(IMG_JFIF);
1170
1171         /* Register the JPEG media type */
1172         dissector_add_string("media_type", "image/jfif", jfif_handle);
1173         dissector_add_string("media_type", "image/jpg", jfif_handle);
1174         dissector_add_string("media_type", "image/jpeg", jfif_handle);
1175
1176         dissector_add_uint("wtap_encap", WTAP_ENCAP_JPEG_JFIF, jfif_handle);
1177
1178         heur_dissector_add("http", dissect_jfif_heur, proto_jfif);
1179 }