#include <string.h> and/or #include <stdio.h> not needed.
[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 /**************** GIF related declarations and definitions ****************/
358
359
360 /************************** Function prototypes **************************/
361
362
363 static void
364 dissect_jfif(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
365
366 void
367 proto_register_jfif(void);
368
369
370
371 /****************** JFIF protocol dissection functions ******************/
372
373 #define ErrorInvalidJFIF "This is not a valid JFIF (JPEG) object"
374
375
376 /*
377  * Process a marker segment (with length).
378  */
379 static void
380 process_marker_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len,
381                 guint16 marker, const char *marker_name)
382 {
383         proto_item *ti = NULL;
384         proto_tree *subtree = NULL;
385
386         if (! tree)
387                 return;
388
389         ti = proto_tree_add_item(tree, hf_marker_segment,
390                         tvb, 0, -1, FALSE);
391         subtree = proto_item_add_subtree(ti, ett_marker_segment);
392
393         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
394         proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
395
396         proto_tree_add_item(subtree, hf_len, tvb, 2, 2, FALSE);
397
398         proto_tree_add_text(subtree, tvb, 4, -1,
399                         "Remaining segment data (%u bytes)", len - 2);
400 }
401
402 /*
403  * Process a Start of Frame header (with length).
404  */
405 static void
406 process_sof_header(proto_tree *tree, tvbuff_t *tvb, guint32 len _U_,
407                 guint16 marker, const char *marker_name)
408 {
409         proto_item *ti = NULL;
410         proto_tree *subtree = NULL;
411
412         if (! tree)
413                 return;
414
415         ti = proto_tree_add_item(tree, hf_sof_header,
416                         tvb, 0, -1, FALSE);
417         subtree = proto_item_add_subtree(ti, ett_marker_segment);
418
419         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
420         proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
421
422         proto_tree_add_item(subtree, hf_len, tvb, 2, 2, FALSE);
423
424         proto_tree_add_item(subtree, hf_sof_precision, tvb, 4, 1, FALSE);
425
426         proto_tree_add_item(subtree, hf_sof_lines, tvb, 5, 2, FALSE);
427
428         proto_tree_add_item(subtree, hf_sof_samples_per_line, tvb, 7, 2, FALSE);
429
430         proto_tree_add_item(subtree, hf_sof_nf, tvb, 9, 1, FALSE);
431         {
432                 guint8 count = tvb_get_guint8(tvb, 9);
433                 guint32 offset = 10;
434                 while (count > 0) {
435                         proto_tree_add_item(subtree, hf_sof_c_i, tvb, offset++, 1, FALSE);
436                         proto_tree_add_item(subtree, hf_sof_h_i, tvb, offset, 1, FALSE);
437                         proto_tree_add_item(subtree, hf_sof_v_i, tvb, offset++, 1, FALSE);
438                         proto_tree_add_item(subtree, hf_sof_tq_i, tvb, offset++, 1, FALSE);
439                         count--;
440                 }
441         }
442 }
443
444 /*
445  * Process a Start of Segment header (with length).
446  */
447 static void
448 process_sos_header(proto_tree *tree, tvbuff_t *tvb, guint32 len _U_,
449                 guint16 marker, const char *marker_name)
450 {
451         proto_item *ti = NULL;
452         proto_tree *subtree = NULL;
453         guint32 offset;
454
455         if (! tree)
456                 return;
457
458         ti = proto_tree_add_item(tree, hf_sos_header,
459                         tvb, 0, -1, FALSE);
460         subtree = proto_item_add_subtree(ti, ett_marker_segment);
461
462         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
463         proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
464
465         proto_tree_add_item(subtree, hf_len, tvb, 2, 2, FALSE);
466
467         proto_tree_add_item(subtree, hf_sos_ns, tvb, 4, 1, FALSE);
468         {
469                 guint8 count = tvb_get_guint8(tvb, 4);
470                 offset = 5;
471                 while (count > 0) {
472                         proto_tree_add_item(subtree, hf_sos_cs_j, tvb, offset++, 1, FALSE);
473                         proto_tree_add_item(subtree, hf_sos_td_j, tvb, offset, 1, FALSE);
474                         proto_tree_add_item(subtree, hf_sos_ta_j, tvb, offset++, 1, FALSE);
475                         count--;
476                 }
477         }
478         
479         proto_tree_add_item(subtree, hf_sos_ss, tvb, offset++, 1, FALSE);
480         proto_tree_add_item(subtree, hf_sos_se, tvb, offset++, 1, FALSE);
481
482         proto_tree_add_item(subtree, hf_sos_ah, tvb, offset, 1, FALSE);
483         proto_tree_add_item(subtree, hf_sos_al, tvb, offset++, 1, FALSE);
484 }
485
486 /* Process an APP0 block.
487  *
488  * XXX - This code only works on US-ASCII systems!!!
489  */
490 static void
491 process_app0_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len,
492                 guint16 marker, const char *marker_name)
493 {
494         proto_item *ti = NULL;
495         proto_tree *subtree = NULL;
496         proto_tree *subtree_details = NULL;
497         guint32 offset;
498         char *str;
499         gint str_size;
500
501         if (!tree)
502                 return;
503
504         ti = proto_tree_add_item(tree, hf_marker_segment,
505                         tvb, 0, -1, FALSE);
506         subtree = proto_item_add_subtree(ti, ett_marker_segment);
507
508         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
509         proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
510
511         proto_tree_add_item(subtree, hf_len, tvb, 2, 2, FALSE);
512
513         str = tvb_get_ephemeral_stringz(tvb, 4, &str_size);
514         ti = proto_tree_add_item(subtree, hf_identifier, tvb, 4, str_size, FALSE);
515         if (strcmp(str, "JFIF") == 0) {
516                 /* Version */
517                 ti = proto_tree_add_none_format(subtree, hf_version,
518                                 tvb, 9, 2, "Version: %u.%u",
519                                 tvb_get_guint8(tvb, 9),
520                                 tvb_get_guint8(tvb, 10));
521                 subtree_details = proto_item_add_subtree(ti, ett_details);
522                 proto_tree_add_item(subtree_details, hf_version_major,
523                                 tvb, 9, 1, FALSE);
524                 proto_tree_add_item(subtree_details, hf_version_minor,
525                                 tvb, 10, 1, FALSE);
526
527                 proto_tree_add_item(subtree, hf_units,
528                                 tvb, 11, 1, FALSE);
529
530                 /* Aspect ratio */
531                 proto_tree_add_item(subtree, hf_xdensity,
532                                 tvb, 12, 2, FALSE);
533                 proto_tree_add_item(subtree, hf_ydensity,
534                                 tvb, 14, 2, FALSE);
535
536                 /* Thumbnail */
537                 proto_tree_add_item(subtree, hf_xthumbnail,
538                                 tvb, 16, 1, FALSE);
539                 proto_tree_add_item(subtree, hf_ythumbnail,
540                                 tvb, 17, 1, FALSE);
541                 {
542                         guint16 x = tvb_get_guint8(tvb, 16);
543                         guint16 y = tvb_get_guint8(tvb, 17);
544                         if (x || y) {
545                                 proto_tree_add_item(subtree, hf_rgb,
546                                                 tvb, 18, 3 * (x * y), FALSE);
547                                 offset = 18 + (3 * (x * y));
548                         } else {
549                                 offset = 18;
550                         }
551                 }
552         } else if (strcmp(str, "JFXX") == 0) {
553                 proto_tree_add_item(subtree, hf_extension_code,
554                                 tvb, 9, 1, FALSE);
555                 {
556                         guint8 code = tvb_get_guint8(tvb, 9);
557                         switch (code) {
558                                 case 0x10: /* Thumbnail coded using JPEG */
559                                         break;
560                                 case 0x11: /* thumbnail stored using 1 byte per pixel */
561                                         break;
562                                 case 0x13: /* thumbnail stored using 3 bytes per pixel */
563                                         break;
564                                 default: /* Error */
565                                         break;
566                         }
567                 }
568         } else { /* Unknown */
569                 proto_item_append_text(ti, " (unknown identifier)");
570                 offset = 4 + str_size;
571
572                 proto_tree_add_text(subtree, tvb, offset, -1,
573                                 "Remaining segment data (%u bytes)", len - 2 - str_size);
574         }
575         return;
576 }
577
578 /* Process an APP1 block.
579  *
580  * XXX - This code only works on US-ASCII systems!!!
581  */
582 static void
583 process_app1_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len,
584                 guint16 marker, const char *marker_name)
585 {
586         proto_item *ti = NULL;
587         proto_tree *subtree = NULL;
588         char *str;
589         gint str_size;
590         int offset = 0;
591         int tiff_start;
592
593         if (!tree)
594                 return;
595
596         ti = proto_tree_add_item(tree, hf_marker_segment,
597                         tvb, 0, -1, FALSE);
598         subtree = proto_item_add_subtree(ti, ett_marker_segment);
599
600         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
601         proto_tree_add_item(subtree, hf_marker, tvb, offset, 2, FALSE);
602         offset += 2;
603
604         proto_tree_add_item(subtree, hf_len, tvb, offset, 2, FALSE);
605         offset += 2;
606
607         str = tvb_get_ephemeral_stringz(tvb, offset, &str_size);
608         ti = proto_tree_add_item(subtree, hf_identifier, tvb, offset, str_size, FALSE);
609         offset += str_size;
610         if (strcmp(str, "Exif") == 0) {
611                 /*
612                  * Endianness
613                  */
614                 gboolean is_little_endian;
615                 guint16 val_16;
616                 guint32 val_32;
617                 guint16 num_fields;
618
619                 offset++; /* Skip a byte supposed to be 0x00 */
620
621                 tiff_start = offset;
622                 val_16 = tvb_get_ntohs(tvb, offset);
623                 if (val_16 == 0x4949) {
624                         is_little_endian = TRUE;
625                         proto_tree_add_text(subtree, tvb, offset, 2, "Endianness: little endian");
626                 } else if (val_16 == 0x4D4D) {
627                         is_little_endian = FALSE;
628                         proto_tree_add_text(subtree, tvb, offset, 2, "Endianness: big endian");
629                 } else {
630                         /* Error: invalid endianness encoding */
631                         proto_tree_add_text(subtree, tvb, offset, 2,
632                                         "Incorrect endianness encoding - skipping the remainder of this application marker");
633                         return;
634                 }
635                 offset += 2;
636                 /*
637                  * Fixed value 42 = 0x002a
638                  */
639                 offset += 2;
640                 /*
641                  * Offset to IFD
642                  */
643                 if (is_little_endian) {
644                         val_32 = tvb_get_letohl(tvb, offset);
645                 } else {
646                         val_32 = tvb_get_ntohl(tvb, offset);
647                 }
648                 /*
649                  * Check for a bogus val_32 value.
650                  * XXX - bogus value message should also deal with a
651                  * value that's too large and causes an overflow.
652                  * Or should it just check against the segment length,
653                  * which is 16 bits?
654                  */
655                 if (val_32 + tiff_start < (guint32)offset + 4) {
656                         proto_tree_add_text(subtree, tvb, offset, 4,
657                             "Start offset of IFD starting from the TIFF header start: %u bytes (bogus, should be >= %u",
658                             val_32, offset + 4 - tiff_start);
659                         return;
660                 }
661                 proto_tree_add_text(subtree, tvb, offset, 4,
662                     "Start offset of IFD starting from the TIFF header start: %u bytes",
663                     val_32);
664                 offset += 4;
665                 /*
666                  * Skip the following portion
667                  */
668                 if (val_32 + tiff_start > (guint32)offset) {
669                         proto_tree_add_text(subtree, tvb, offset, val_32 + tiff_start - offset,
670                             "Skipped data between end of TIFF header and start of IFD (%u bytes)",
671                             val_32 + tiff_start - offset);
672                 }
673                 for (;;) {
674                         offset = val_32 + tiff_start;
675                         /*
676                          * Process the IFD
677                          */
678                         if (is_little_endian) {
679                                 num_fields = tvb_get_letohs(tvb, offset);
680                         } else {
681                                 num_fields = tvb_get_ntohs(tvb, offset);
682                         }
683                         proto_tree_add_text(subtree, tvb, offset, 2, "Number of fields in this IFD: %u", num_fields);
684                         offset += 2;
685                         while (num_fields-- > 0) {
686                                 guint16 tag, type;
687                                 guint32 count, off;
688
689                                 if (is_little_endian) {
690                                         tag = tvb_get_letohs(tvb, offset);
691                                         type = tvb_get_letohs(tvb, offset + 2);
692                                         count = tvb_get_letohl(tvb, offset + 4);
693                                         off = tvb_get_letohl(tvb, offset + 8);
694                                 } else {
695                                         tag = tvb_get_ntohs(tvb, offset);
696                                         type = tvb_get_ntohs(tvb, offset + 2);
697                                         count = tvb_get_ntohl(tvb, offset + 4);
698                                         off = tvb_get_ntohl(tvb, offset + 8);
699                                 }
700                                 /* TODO - refine this */
701                                 proto_tree_add_text(subtree, tvb, offset, 2,
702                                     "Exif Tag: 0x%04X (%s), Type: %u (%s), Count: %u, "
703                                     "Value offset from start of TIFF header: %u",
704                                     tag, val_to_str(tag, vals_exif_tags, "Unknown Exif tag"),
705                                     type, val_to_str(type, vals_exif_types, "Unknown Exif type"),
706                                     count, off);
707                                 offset += 12;
708                         }
709                         /*
710                          * Offset to the next IFD
711                          */
712                         if (is_little_endian) {
713                                 val_32 = tvb_get_letohl(tvb, offset);
714                         } else {
715                                 val_32 = tvb_get_ntohl(tvb, offset);
716                         }
717                         if (val_32 != 0 &&
718                             val_32 + tiff_start < (guint32)offset + 4) {
719                                 proto_tree_add_text(subtree, tvb, offset, 4,
720                                     "Offset to next IFD from start of TIFF header: %u bytes (bogus, should be >= %u)",
721                                     val_32, offset + 4 - tiff_start);
722                                 return;
723                         }
724                         proto_tree_add_text(subtree, tvb, offset, 4,
725                             "Offset to next IFD from start of TIFF header: %u bytes",
726                             val_32);
727                         offset += 4;
728                         if (val_32 == 0)
729                                 break;
730                 }
731         } else {
732                 proto_tree_add_text(subtree, tvb, offset, -1,
733                                 "Remaining segment data (%u bytes)", len - 2 - str_size);
734                 proto_item_append_text(ti, " (Unknown identifier)");
735         }
736 }
737
738 /* Process an APP2 block.
739  *
740  * XXX - This code only works on US-ASCII systems!!!
741  */
742 static void
743 process_app2_segment(proto_tree *tree, tvbuff_t *tvb, guint32 len,
744                 guint16 marker, const char *marker_name)
745 {
746         proto_item *ti = NULL;
747         proto_tree *subtree = NULL;
748         char *str;
749         gint str_size;
750
751         if (!tree)
752                 return;
753
754         ti = proto_tree_add_item(tree, hf_marker_segment,
755                         tvb, 0, -1, FALSE);
756         subtree = proto_item_add_subtree(ti, ett_marker_segment);
757
758         proto_item_append_text(ti, ": %s (0x%04X)", marker_name, marker);
759         proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
760
761         proto_tree_add_item(subtree, hf_len, tvb, 2, 2, FALSE);
762
763         str = tvb_get_ephemeral_stringz(tvb, 4, &str_size);
764         ti = proto_tree_add_item(subtree, hf_identifier, tvb, 4, str_size, FALSE);
765         if (strcmp(str, "FPXR") == 0) {
766                 proto_tree_add_text(tree, tvb, 0, -1, "Exif FlashPix APP2 application marker");
767         } else {
768                 proto_tree_add_text(subtree, tvb, 4 + str_size, -1,
769                                 "Remaining segment data (%u bytes)", len - 2 - str_size);
770                 proto_item_append_text(ti, " (Unknown identifier)");
771         }
772 }
773
774 static void
775 dissect_jfif(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
776 {
777         proto_tree *subtree = NULL;
778         proto_item *ti;
779         guint tvb_len = tvb_reported_length(tvb);
780         guint32 offset = 0;
781         tvbuff_t *tmp_tvb;
782         guint32 len;
783         guint16 marker;
784
785         /* Add summary to INFO column if it is enabled */
786         if (check_col(pinfo->cinfo, COL_INFO))
787                 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(JPEG JFIF image)");
788
789         if (tree) {
790                 ti = proto_tree_add_item(tree, proto_jfif,
791                                 tvb, 0, -1, FALSE);
792                 subtree = proto_item_add_subtree(ti, ett_jfif);
793         }
794
795         marker = tvb_get_ntohs(tvb, 0);
796         if (marker != MARKER_SOI) {
797                 if (tree) {
798                         proto_tree_add_text(subtree, tvb, 0, 2, ErrorInvalidJFIF);
799                         return;
800                 }
801         }
802         if (tree)
803                 proto_tree_add_item(subtree, hf_marker, tvb, 0, 2, FALSE);
804
805         offset = 2;
806
807         /*
808          * Process the remaining markers and marker segments
809          */
810         while (offset < tvb_len) {
811                 const char *str;
812                 marker = tvb_get_ntohs(tvb, offset);
813                 str = match_strval(marker, vals_marker);
814                 if (str) { /* Known marker */
815                         if (marker_has_length(marker)) { /* Marker segment */
816                                 /* Length of marker segment = 2 + len */
817                                 len = tvb_get_ntohs(tvb, offset + 2);
818                                 tmp_tvb = tvb_new_subset(tvb, offset, 2 + len, 2 + len);
819                                 switch (marker) {
820                                         case MARKER_APP0:
821                                                 process_app0_segment(subtree, tmp_tvb, len, marker, str);
822                                                 break;
823                                         case MARKER_APP1:
824                                                 process_app1_segment(subtree, tmp_tvb, len, marker, str);
825                                                 break;
826                                         case MARKER_APP2:
827                                                 process_app2_segment(subtree, tmp_tvb, len, marker, str);
828                                                 break;
829                                         case MARKER_SOF0:
830                                         case MARKER_SOF1:
831                                         case MARKER_SOF2:
832                                         case MARKER_SOF3:
833                                         case MARKER_SOF5:
834                                         case MARKER_SOF6:
835                                         case MARKER_SOF7:
836                                         case MARKER_SOF8:
837                                         case MARKER_SOF9:
838                                         case MARKER_SOF10:
839                                         case MARKER_SOF11:
840                                         case MARKER_SOF13:
841                                         case MARKER_SOF14:
842                                         case MARKER_SOF15:
843                                                 process_sof_header(subtree, tmp_tvb, len, marker, str);
844                                                 break;
845                                         case MARKER_SOS:
846                                                 process_sos_header(subtree, tmp_tvb, len, marker, str);
847                                                 /*
848                                                  * TODO - dissect a scan; the scan data is encoded.
849                                                  */
850                                                 proto_tree_add_text(subtree, tvb, offset + 2 + len, -1,
851                                                                 "JFIF dissection stops here (dissection of a scan is not yet implemented)");
852                                                 return;
853                                                 break;
854                                         default:
855                                                 process_marker_segment(subtree, tmp_tvb, len, marker, str);
856                                                 break;
857                                 }
858                                 offset += 2 + len;
859                         } else { /* Marker but no segment */
860                                 /* Length = 2 */
861                                 proto_tree_add_item(subtree, hf_marker,
862                                                 tvb, offset, 2, FALSE);
863                                 offset += 2;
864                         }
865                 } else { /* Reserved! */
866                         ti = proto_tree_add_item(subtree, hf_marker,
867                                         tvb, offset, 2, FALSE);
868                         proto_item_append_text(ti, " (Reserved)");
869                         return;
870                 }
871         }
872
873         return;
874 }
875
876
877 /****************** Register the protocol with Wireshark ******************/
878
879
880 /* This format is required because a script is used to build the C function
881  * that calls the protocol registration. */
882
883 void
884 proto_register_jfif(void)
885 {
886         /*
887          * Setup list of header fields.
888          */
889         static hf_register_info hf[] = {
890                 /* Marker */
891                 { &hf_marker,
892                         {       "Marker",
893                                 IMG_JFIF ".marker",
894                                 FT_UINT8, BASE_HEX, VALS(vals_marker), 0x00,
895                                 "JFIF Marker",
896                                 HFILL
897                         }
898                 },
899                 /* Marker segment */
900                 { &hf_marker_segment,
901                         {       "Marker segment",
902                                 IMG_JFIF "marker_segment",
903                                 FT_NONE, BASE_NONE, NULL, 0x00,
904                                 NULL,
905                                 HFILL
906                         }
907                 },
908                 { &hf_len,
909                         {       "Length",
910                                 IMG_JFIF ".length",
911                                 FT_UINT16, BASE_DEC, 0, 0x00,
912                                 "Length of segment (including length field)",
913                                 HFILL
914                         }
915                 },
916                 /* MARKER_APP0 */
917                 { &hf_identifier,
918                         {       "Identifier",
919                                 IMG_JFIF ".identifier",
920                                 FT_STRINGZ, BASE_NONE, NULL, 0x00,
921                                 "Identifier of the segment",
922                                 HFILL
923                         }
924                 },
925                 /* MARKER_APP0 - JFIF */
926                 { &hf_version,
927                         {       "Version",
928                                 IMG_JFIF ".version",
929                                 FT_NONE, BASE_NONE, NULL, 0x00,
930                                 "JFIF Version",
931                                 HFILL
932                         }
933                 },
934                 { &hf_version_major,
935                         {       "Major Version",
936                                 IMG_JFIF ".version.major",
937                                 FT_UINT8, BASE_DEC, NULL, 0x00,
938                                 "JFIF Major Version",
939                                 HFILL
940                         }
941                 },
942                 { &hf_version_minor,
943                         {       "Minor Version",
944                                 IMG_JFIF ".version.minor",
945                                 FT_UINT8, BASE_DEC, NULL, 0x00,
946                                 "JFIF Minor Version",
947                                 HFILL
948                         }
949                 },
950                 { &hf_units,
951                         {       "Units",
952                                 IMG_JFIF ".units",
953                                 FT_UINT8, BASE_DEC, VALS(vals_units), 0x00,
954                                 "Units used in this segment",
955                                 HFILL
956                         }
957                 },
958                 { &hf_xdensity,
959                         {       "Xdensity",
960                                 IMG_JFIF ".Xdensity",
961                                 FT_UINT16, BASE_DEC, NULL, 0x00,
962                                 "Horizontal pixel density",
963                                 HFILL
964                         }
965                 },
966                 { &hf_ydensity,
967                         {       "Ydensity",
968                                 IMG_JFIF ".Ydensity",
969                                 FT_UINT16, BASE_DEC, NULL, 0x00,
970                                 "Vertical pixel density",
971                                 HFILL
972                         }
973                 },
974                 { &hf_xthumbnail,
975                         {       "Xthumbnail",
976                                 IMG_JFIF ".Xthumbnail",
977                                 FT_UINT16, BASE_DEC, NULL, 0x00,
978                                 "Thumbnail horizontal pixel count",
979                                 HFILL
980                         }
981                 },
982                 { &hf_ythumbnail,
983                         {       "Ythumbnail",
984                                 IMG_JFIF ".Ythumbnail",
985                                 FT_UINT16, BASE_DEC, NULL, 0x00,
986                                 "Thumbnail vertical pixel count",
987                                 HFILL
988                         }
989                 },
990                 { &hf_rgb,
991                         {       "RGB values of thumbnail pixels",
992                                 IMG_JFIF ".RGB",
993                                 FT_BYTES, BASE_NONE, NULL, 0x00,
994                                 "RGB values of the thumbnail pixels (24 bit per pixel, Xthumbnail x Ythumbnail pixels)",
995                                 HFILL
996                         }
997                 },
998                 /* MARKER_APP0 - JFXX */
999                 { &hf_extension_code,
1000                         {       "Extension code",
1001                                 IMG_JFIF ".extension.code",
1002                                 FT_UINT8, BASE_HEX, VALS(vals_extension_code), 0x00,
1003                                 "JFXX extension code for thumbnail encoding",
1004                                 HFILL
1005                         }
1006                 },
1007                 /* Header: Start of Frame (MARKER_SOF) */
1008                 { &hf_sof_header,
1009                         {       "Start of Frame header",
1010                                 IMG_JFIF ".sof",
1011                                 FT_NONE, BASE_NONE, NULL, 0x00,
1012                                 NULL,
1013                                 HFILL
1014                         }
1015                 },
1016                 { &hf_sof_precision,
1017                         {       "Sample Precision (bits)",
1018                                 IMG_JFIF ".sof.precision",
1019                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1020                                 "Specifies the precision in bits for the samples of the components in the frame.",
1021                                 HFILL
1022                         }
1023                 },
1024                 { &hf_sof_lines,
1025                         {       "Lines",
1026                                 IMG_JFIF ".sof.lines",
1027                                 FT_UINT16, BASE_DEC, NULL, 0x00,
1028                                 "Specifies the maximum number of lines in the source image.",
1029                                 HFILL
1030                         }
1031                 },
1032                 { &hf_sof_samples_per_line,
1033                         {       "Samples per line",
1034                                 IMG_JFIF ".sof.samples_per_line",
1035                                 FT_UINT16, BASE_DEC, NULL, 0x00,
1036                                 "Specifies the maximum number of samples per line in the source image.",
1037                                 HFILL
1038                         }
1039                 },
1040                 { &hf_sof_nf,
1041                         {       "Number of image components in frame",
1042                                 IMG_JFIF ".sof.nf",
1043                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1044                                 "Specifies the number of source image components in the frame.",
1045                                 HFILL
1046                         }
1047                 },
1048                 { &hf_sof_c_i,
1049                         {       "Component identifier",
1050                                 IMG_JFIF ".sof.c_i",
1051                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1052                                 "Assigns a unique label to the ith component in the sequence of frame component specification parameters.",
1053                                 HFILL
1054                         }
1055                 },
1056                 { &hf_sof_h_i,
1057                         {       "Horizontal sampling factor",
1058                                 IMG_JFIF ".sof.h_i",
1059                                 FT_UINT8, BASE_DEC, NULL, 0xF0,
1060                                 "Specifies the relationship between the component horizontal dimension and maximum image dimension X.",
1061                                 HFILL
1062                         }
1063                 },
1064                 { &hf_sof_v_i,
1065                         {       "Vertical sampling factor",
1066                                 IMG_JFIF ".sof.v_i",
1067                                 FT_UINT8, BASE_DEC, NULL, 0x0F,
1068                                 "Specifies the relationship between the component vertical dimension and maximum image dimension Y.",                           
1069                                 HFILL
1070                         }
1071                 },
1072                 { &hf_sof_tq_i,
1073                         {       "Quantization table destination selector",
1074                                 IMG_JFIF ".sof.tq_i",
1075                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1076                                 "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.",
1077                                 HFILL
1078                         }
1079                 },
1080
1081                 /* Header: Start of Segment (MARKER_SOS) */
1082                 { &hf_sos_header,
1083                         {       "Start of Segment header",
1084                                 IMG_JFIF ".header.sos",
1085                                 FT_NONE, BASE_NONE, NULL, 0x00,
1086                                 NULL,
1087                                 HFILL
1088                         }
1089                 },
1090                 { &hf_sos_ns,
1091                         {       "Number of image components in scan",
1092                                 IMG_JFIF ".sos.ns",
1093                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1094                                 "Specifies the number of source image components in the scan.",
1095                                 HFILL
1096                         }
1097                 },
1098                 { &hf_sos_cs_j,
1099                         {       "Scan component selector",
1100                                 IMG_JFIF ".sos.component_selector",
1101                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1102                                 "Selects which of the Nf image components specified in the frame parameters shall be the jth component in the scan.",
1103                                 HFILL
1104                         }
1105                 },
1106                 { &hf_sos_td_j,
1107                         {       "DC entropy coding table destination selector",
1108                                 IMG_JFIF ".sos.dc_entropy_selector",
1109                                 FT_UINT8, BASE_DEC, NULL, 0xF0,
1110                                 "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.",
1111                                 HFILL
1112                         }
1113                 },
1114                 { &hf_sos_ta_j,
1115                         {       "AC entropy coding table destination selector",
1116                                 IMG_JFIF ".sos.ac_entropy_selector",
1117                                 FT_UINT8, BASE_DEC, NULL, 0x0F,
1118                                 "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.",
1119                                 HFILL
1120                         }
1121                 },
1122                 { &hf_sos_ss,
1123                         {       "Start of spectral or predictor selection",
1124                                 IMG_JFIF ".sos.ss",
1125                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1126                                 "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.",
1127                                 HFILL
1128                         }
1129                 },
1130                 { &hf_sos_se,
1131                         {       "End of spectral selection",
1132                                 IMG_JFIF ".sos.se",
1133                                 FT_UINT8, BASE_DEC, NULL, 0x00,
1134                                 "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.",
1135                                 HFILL
1136                         }
1137                 },
1138                 { &hf_sos_ah,
1139                         {       "Successive approximation bit position high",
1140                                 IMG_JFIF ".sos.ah",
1141                                 FT_UINT8, BASE_DEC, NULL, 0xF0,
1142                                 "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.",
1143                                 HFILL
1144                         }
1145                 },
1146                 { &hf_sos_al, 
1147                         {       "Successive approximation bit position low or point transform",
1148                                 IMG_JFIF ".sos.al",
1149                                 FT_UINT8, BASE_DEC, NULL, 0x0F,
1150                                 "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.",
1151                                 HFILL
1152                         }
1153                 },
1154         };
1155
1156         /* Setup protocol subtree array */
1157         static gint *ett[] = {
1158                 &ett_jfif,
1159                 &ett_marker_segment,
1160                 &ett_details,
1161         };
1162
1163         /* Register the protocol name and description */
1164         proto_jfif = proto_register_protocol(
1165                         "JPEG File Interchange Format",
1166                         "JFIF (JPEG) image",
1167                         IMG_JFIF
1168         );
1169
1170         /* Required function calls to register the header fields
1171          * and subtrees used */
1172         proto_register_field_array(proto_jfif, hf, array_length(hf));
1173         proto_register_subtree_array(ett, array_length(ett));
1174
1175         register_dissector("image-jfif", dissect_jfif, proto_jfif);
1176 }
1177
1178
1179 void
1180 proto_reg_handoff_jfif(void)
1181 {
1182         dissector_handle_t jfif_handle;
1183
1184         jfif_handle = find_dissector("image-jfif");
1185
1186         /* Register the JPEG media type */
1187         dissector_add_string("media_type", "image/jfif", jfif_handle);
1188         dissector_add_string("media_type", "image/jpg", jfif_handle);
1189         dissector_add_string("media_type", "image/jpeg", jfif_handle);
1190
1191         dissector_add("wtap_encap", WTAP_ENCAP_JPEG_JFIF, jfif_handle);
1192 }