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