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