1 /* file-png.c
2 *
3 * Routines for PNG (Portable Network Graphics) image file dissection
4 *
5 * Copyright 2006 Ronnie Sahlberg
6 *
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
10 *
11 * SPDX-License-Identifier: GPL-2.0-or-later
12 */
13 /* See http://www.w3.org/TR/PNG for specification
14 */
15
16 #define NEW_PROTO_TREE_API
17
18 #include "config.h"
19
20 #include <epan/packet.h>
21 #include <epan/expert.h>
22
23
24 #define MAKE_TYPE_VAL(a, b, c, d) ((a)<<24 | (b)<<16 | (c)<<8 | (d))
25
26 #define CHUNK_TYPE_IHDR MAKE_TYPE_VAL('I', 'H', 'D', 'R')
27 #define CHUNK_TYPE_bKGD MAKE_TYPE_VAL('b', 'K', 'G', 'D')
28 #define CHUNK_TYPE_gAMA MAKE_TYPE_VAL('g', 'A', 'M', 'A')
29 #define CHUNK_TYPE_iCCP MAKE_TYPE_VAL('i', 'C', 'C', 'P')
30 #define CHUNK_TYPE_cHRM MAKE_TYPE_VAL('c', 'H', 'R', 'M')
31 #define CHUNK_TYPE_pHYs MAKE_TYPE_VAL('p', 'H', 'Y', 's')
32 #define CHUNK_TYPE_iTXt MAKE_TYPE_VAL('i', 'T', 'X', 't')
33 #define CHUNK_TYPE_tEXt MAKE_TYPE_VAL('t', 'E', 'X', 't')
34 #define CHUNK_TYPE_sBIT MAKE_TYPE_VAL('s', 'B', 'I', 'T')
35 #define CHUNK_TYPE_sRGB MAKE_TYPE_VAL('s', 'R', 'G', 'B')
36 #define CHUNK_TYPE_tIME MAKE_TYPE_VAL('t', 'I', 'M', 'E')
37 #define CHUNK_TYPE_IDAT MAKE_TYPE_VAL('I', 'D', 'A', 'T')
38 #define CHUNK_TYPE_IEND MAKE_TYPE_VAL('I', 'E', 'N', 'D')
39 #define CHUNK_TYPE_tRNS MAKE_TYPE_VAL('t', 'R', 'N', 'S')
40 #define CHUNK_TYPE_PLTE MAKE_TYPE_VAL('P', 'L', 'T', 'E')
41
42 static const value_string chunk_types[] = {
43 { CHUNK_TYPE_IHDR, "Image Header" },
44 { CHUNK_TYPE_bKGD, "Background colour" },
45 { CHUNK_TYPE_gAMA, "Image gamma" },
46 { CHUNK_TYPE_iCCP, "Embedded ICC profile" },
47 { CHUNK_TYPE_cHRM, "Primary chromaticities and white point" },
48 { CHUNK_TYPE_pHYs, "Physical pixel dimensions" },
49 { CHUNK_TYPE_iTXt, "International textual data" },
50 { CHUNK_TYPE_tEXt, "Textual data" },
51 { CHUNK_TYPE_sBIT, "Significant bits" },
52 { CHUNK_TYPE_sRGB, "Standard RGB colour space" },
53 { CHUNK_TYPE_tIME, "Image last-modification time" },
54 { CHUNK_TYPE_IDAT, "Image data chunk" },
55 { CHUNK_TYPE_IEND, "Image Trailer" },
56 { CHUNK_TYPE_tRNS, "Transparency" },
57 { CHUNK_TYPE_PLTE, "Palette" },
58 { 0, NULL }
59 };
60
61
62 void proto_register_png(void);
63 void proto_reg_handoff_png(void);
64
65 static header_field_info *hfi_png = NULL;
66
67 #define PNG_HFI_INIT HFI_INIT(proto_png)
68
69 static header_field_info hfi_png_signature PNG_HFI_INIT = {
70 "PNG Signature", "png.signature", FT_BYTES, BASE_NONE,
71 NULL, 0, NULL, HFILL };
72
73 static header_field_info hfi_png_chunk_data PNG_HFI_INIT = {
74 "Data", "png.chunk.data", FT_NONE, BASE_NONE,
75 NULL, 0, NULL, HFILL };
76
77 static header_field_info hfi_png_chunk_type_str PNG_HFI_INIT = {
78 "Chunk", "png.chunk.type", FT_STRING, BASE_NONE,
79 NULL, 0, NULL, HFILL };
80
81 static header_field_info hfi_png_chunk_len PNG_HFI_INIT = {
82 "Len", "png.chunk.len", FT_UINT32, BASE_DEC,
83 NULL, 0, NULL, HFILL };
84
85 static header_field_info hfi_png_chunk_crc PNG_HFI_INIT = {
86 "CRC", "png.chunk.crc", FT_UINT32, BASE_HEX,
87 NULL, 0, NULL, HFILL };
88
89 static const true_false_string png_chunk_anc = {
90 "This is an ANCILLARY chunk",
91 "This is a CRITICAL chunk"
92 };
93
94 static header_field_info hfi_png_chunk_flag_anc PNG_HFI_INIT = {
95 "Ancillary", "png.chunk.flag.ancillary", FT_BOOLEAN, 32,
96 TFS(&png_chunk_anc), 0x20000000, NULL, HFILL };
97
98 static const true_false_string png_chunk_priv = {
99 "This is a PRIVATE chunk",
100 "This is a PUBLIC chunk"
101 };
102
103 static header_field_info hfi_png_chunk_flag_priv PNG_HFI_INIT = {
104 "Private", "png.chunk.flag.private", FT_BOOLEAN, 32,
105 TFS(&png_chunk_priv), 0x00200000, NULL, HFILL };
106
107 static const true_false_string png_chunk_stc = {
108 "This chunk is SAFE TO COPY",
109 "This chunk is NOT safe to copy"
110 };
111
112 static header_field_info hfi_png_chunk_flag_stc PNG_HFI_INIT = {
113 "Safe To Copy", "png.chunk.flag.stc", FT_BOOLEAN, 32,
114 TFS(&png_chunk_stc), 0x00000020, NULL, HFILL };
115
116 static header_field_info hfi_png_ihdr_width PNG_HFI_INIT = {
117 "Width", "png.ihdr.width", FT_UINT32, BASE_DEC,
118 NULL, 0, NULL, HFILL };
119
120 static header_field_info hfi_png_ihdr_height PNG_HFI_INIT = {
121 "Height", "png.ihdr.height", FT_UINT32, BASE_DEC,
122 NULL, 0, NULL, HFILL };
123
124 static header_field_info hfi_png_ihdr_bitdepth PNG_HFI_INIT = {
125 "Bit Depth", "png.ihdr.bitdepth", FT_UINT8, BASE_DEC,
126 NULL, 0, NULL, HFILL };
127
128 static const value_string colour_type_vals[] = {
129 { 0, "Greyscale"},
130 { 2, "Truecolour"},
131 { 3, "Indexed-colour"},
132 { 4, "Greyscale with alpha"},
133 { 6, "Truecolour with alpha"},
134 { 0, NULL }
135 };
136
137 static header_field_info hfi_png_ihdr_colour_type PNG_HFI_INIT = {
138 "Colour Type", "png.ihdr.colour_type", FT_UINT8, BASE_DEC,
139 VALS(colour_type_vals), 0, NULL, HFILL };
140
141 static const value_string compression_method_vals[] = {
142 { 0, "Deflate"},
143 { 0, NULL }
144 };
145
146 static header_field_info hfi_png_ihdr_compression_method PNG_HFI_INIT = {
147 "Compression Method", "png.ihdr.compression_method", FT_UINT8, BASE_DEC,
148 VALS(compression_method_vals), 0, NULL, HFILL };
149
150 static const value_string filter_method_vals[] = {
151 { 0, "Adaptive"},
152 { 0, NULL }
153 };
154
155 static header_field_info hfi_png_ihdr_filter_method PNG_HFI_INIT = {
156 "Filter Method", "png.ihdr.filter_method", FT_UINT8, BASE_DEC,
157 VALS(filter_method_vals), 0, NULL, HFILL };
158
159 static const value_string interlace_method_vals[] = {
160 { 0, "No interlace"},
161 { 1, "Adam7"},
162 { 0, NULL }
163 };
164
165 static header_field_info hfi_png_ihdr_interlace_method PNG_HFI_INIT = {
166 "Interlace Method", "png.ihdr.interlace_method", FT_UINT8, BASE_DEC,
167 VALS(interlace_method_vals), 0, NULL, HFILL };
168
169 static const value_string srgb_intent_vals[] = {
170 { 0, "Perceptual" },
171 { 1, "Relative colorimetric" },
172 { 2, "Saturation" },
173 { 3, "Absolute colorimetric" },
174 { 0, NULL }
175 };
176
177 static header_field_info hfi_png_srgb_intent PNG_HFI_INIT = {
178 "Intent", "png.srgb.intent", FT_UINT8, BASE_DEC,
179 VALS(srgb_intent_vals), 0, NULL, HFILL };
180
181 static header_field_info hfi_png_text_keyword PNG_HFI_INIT = {
182 "Keyword", "png.text.keyword", FT_STRING, STR_UNICODE,
183 NULL, 0, NULL, HFILL };
184
185 static header_field_info hfi_png_text_string PNG_HFI_INIT = {
186 "String", "png.text.string", FT_STRING, STR_UNICODE,
187 NULL, 0, NULL, HFILL };
188
189 static header_field_info hfi_png_time_year PNG_HFI_INIT = {
190 "Year", "png.time.year", FT_UINT16, BASE_DEC,
191 NULL, 0, NULL, HFILL };
192
193 static header_field_info hfi_png_time_month PNG_HFI_INIT = {
194 "Month", "png.time.month", FT_UINT8, BASE_DEC,
195 NULL, 0, NULL, HFILL };
196
197 static header_field_info hfi_png_time_day PNG_HFI_INIT = {
198 "Day", "png.time.day", FT_UINT8, BASE_DEC,
199 NULL, 0, NULL, HFILL };
200
201 static header_field_info hfi_png_time_hour PNG_HFI_INIT = {
202 "Hour", "png.time.hour", FT_UINT8, BASE_DEC,
203 NULL, 0, NULL, HFILL };
204
205 static header_field_info hfi_png_time_minute PNG_HFI_INIT = {
206 "Minute", "png.time.minute", FT_UINT8, BASE_DEC,
207 NULL, 0, NULL, HFILL };
208
209 static header_field_info hfi_png_time_second PNG_HFI_INIT = {
210 "Second", "png.time.second", FT_UINT8, BASE_DEC,
211 NULL, 0, NULL, HFILL };
212
213 static header_field_info hfi_png_phys_horiz PNG_HFI_INIT = {
214 "Horizontal pixels per unit", "png.phys.horiz", FT_UINT32, BASE_DEC,
215 NULL, 0, NULL, HFILL };
216
217 static header_field_info hfi_png_phys_vert PNG_HFI_INIT = {
218 "Vertical pixels per unit", "png.phys.vert", FT_UINT32, BASE_DEC,
219 NULL, 0, NULL, HFILL };
220
221 static const value_string phys_unit_vals[] = {
222 { 0, "Unit is unknown"},
223 { 1, "Unit is METRE"},
224 { 0, NULL }
225 };
226
227 static header_field_info hfi_png_phys_unit PNG_HFI_INIT = {
228 "Unit", "png.phys.unit", FT_UINT8, BASE_DEC,
229 VALS(phys_unit_vals), 0, NULL, HFILL };
230
231 static header_field_info hfi_png_bkgd_palette_index PNG_HFI_INIT = {
232 "Palette Index", "png.bkgd.palette_index", FT_UINT8, BASE_DEC,
233 NULL, 0, NULL, HFILL };
234
235 static header_field_info hfi_png_bkgd_greyscale PNG_HFI_INIT = {
236 "Greyscale", "png.bkgd.greyscale", FT_UINT16, BASE_HEX,
237 NULL, 0, NULL, HFILL };
238
239 static header_field_info hfi_png_bkgd_red PNG_HFI_INIT = {
240 "Red", "png.bkgd.red", FT_UINT16, BASE_HEX,
241 NULL, 0, NULL, HFILL };
242
243 static header_field_info hfi_png_bkgd_green PNG_HFI_INIT = {
244 "Green", "png.bkgd.green", FT_UINT16, BASE_HEX,
245 NULL, 0, NULL, HFILL };
246
247 static header_field_info hfi_png_bkgd_blue PNG_HFI_INIT = {
248 "Blue", "png.bkgd.blue", FT_UINT16, BASE_HEX,
249 NULL, 0, NULL, HFILL };
250
251 static header_field_info hfi_png_chrm_white_x PNG_HFI_INIT = {
252 "White X", "png.chrm.white.x", FT_FLOAT, BASE_NONE,
253 NULL, 0, NULL, HFILL };
254
255 static header_field_info hfi_png_chrm_white_y PNG_HFI_INIT = {
256 "White Y", "png.chrm.white.y", FT_FLOAT, BASE_NONE,
257 NULL, 0, NULL, HFILL };
258
259 static header_field_info hfi_png_chrm_red_x PNG_HFI_INIT = {
260 "Red X", "png.chrm.red.x", FT_FLOAT, BASE_NONE,
261 NULL, 0, NULL, HFILL };
262
263 static header_field_info hfi_png_chrm_red_y PNG_HFI_INIT = {
264 "Red Y", "png.chrm.red.y", FT_FLOAT, BASE_NONE,
265 NULL, 0, NULL, HFILL };
266
267 static header_field_info hfi_png_chrm_green_x PNG_HFI_INIT = {
268 "Green X", "png.chrm.green.x", FT_FLOAT, BASE_NONE,
269 NULL, 0, NULL, HFILL };
270
271 static header_field_info hfi_png_chrm_green_y PNG_HFI_INIT = {
272 "Green Y", "png.chrm.green.y", FT_FLOAT, BASE_NONE,
273 NULL, 0, NULL, HFILL };
274
275 static header_field_info hfi_png_chrm_blue_x PNG_HFI_INIT = {
276 "Blue X", "png.chrm.blue.x", FT_FLOAT, BASE_NONE,
277 NULL, 0, NULL, HFILL };
278
279 static header_field_info hfi_png_chrm_blue_y PNG_HFI_INIT = {
280 "Blue Y", "png.chrm.blue.y", FT_FLOAT, BASE_NONE,
281 NULL, 0, NULL, HFILL };
282
283 static header_field_info hfi_png_gama_gamma PNG_HFI_INIT = {
284 "Gamma", "png.gama.gamma", FT_FLOAT, BASE_NONE,
285 NULL, 0, NULL, HFILL };
286
287 static gint ett_png = -1;
288 static gint ett_png_chunk = -1;
289
290 static expert_field ei_png_chunk_too_large = EI_INIT;
291
292 static dissector_handle_t png_handle;
293
294 static void
dissect_png_ihdr(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree)295 dissect_png_ihdr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
296 {
297 proto_tree_add_item(tree, &hfi_png_ihdr_width, tvb, 0, 4, ENC_BIG_ENDIAN);
298 proto_tree_add_item(tree, &hfi_png_ihdr_height, tvb, 4, 4, ENC_BIG_ENDIAN);
299 proto_tree_add_item(tree, &hfi_png_ihdr_bitdepth, tvb, 8, 1, ENC_BIG_ENDIAN);
300 proto_tree_add_item(tree, &hfi_png_ihdr_colour_type, tvb, 9, 1, ENC_BIG_ENDIAN);
301 proto_tree_add_item(tree, &hfi_png_ihdr_compression_method, tvb, 10, 1, ENC_BIG_ENDIAN);
302 proto_tree_add_item(tree, &hfi_png_ihdr_filter_method, tvb, 11, 1, ENC_BIG_ENDIAN);
303 proto_tree_add_item(tree, &hfi_png_ihdr_interlace_method, tvb, 12, 1, ENC_BIG_ENDIAN);
304
305 }
306
307 static void
dissect_png_srgb(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree)308 dissect_png_srgb(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
309 {
310 proto_tree_add_item(tree, &hfi_png_srgb_intent,
311 tvb, 0, 1, ENC_BIG_ENDIAN);
312 }
313
314 static void
dissect_png_text(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree)315 dissect_png_text(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
316 {
317 gint offset=0, nul_offset;
318
319 nul_offset = tvb_find_guint8(tvb, offset, tvb_captured_length_remaining(tvb, offset), 0);
320 /* nul_offset == 0 means empty keyword, this is not allowed by the png standard */
321 if (nul_offset<=0) {
322 /* XXX exception */
323 return;
324 }
325
326 proto_tree_add_item(tree, &hfi_png_text_keyword, tvb, offset, nul_offset, ENC_ISO_8859_1|ENC_NA);
327 offset = nul_offset+1; /* length of the key word + 0 character */
328
329 proto_tree_add_item(tree, &hfi_png_text_string, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_ISO_8859_1|ENC_NA);
330
331 }
332
333 static void
dissect_png_time(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree)334 dissect_png_time(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
335 {
336 proto_tree_add_item(tree, &hfi_png_time_year, tvb, 0, 2, ENC_BIG_ENDIAN);
337 proto_tree_add_item(tree, &hfi_png_time_month, tvb, 2, 1, ENC_BIG_ENDIAN);
338 proto_tree_add_item(tree, &hfi_png_time_day, tvb, 3, 1, ENC_BIG_ENDIAN);
339 proto_tree_add_item(tree, &hfi_png_time_hour, tvb, 4, 1, ENC_BIG_ENDIAN);
340 proto_tree_add_item(tree, &hfi_png_time_minute, tvb, 5, 1, ENC_BIG_ENDIAN);
341 proto_tree_add_item(tree, &hfi_png_time_second, tvb, 6, 1, ENC_BIG_ENDIAN);
342 }
343
344 static void
dissect_png_phys(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree)345 dissect_png_phys(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
346 {
347 proto_tree_add_item(tree, &hfi_png_phys_horiz, tvb, 0, 4, ENC_BIG_ENDIAN);
348 proto_tree_add_item(tree, &hfi_png_phys_vert, tvb, 4, 4, ENC_BIG_ENDIAN);
349 proto_tree_add_item(tree, &hfi_png_phys_unit, tvb, 8, 1, ENC_BIG_ENDIAN);
350 }
351
352 static void
dissect_png_bkgd(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree)353 dissect_png_bkgd(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
354 {
355 switch(tvb_reported_length(tvb)){
356 case 1: /* colour type 3 */
357 proto_tree_add_item(tree, &hfi_png_bkgd_palette_index, tvb, 0, 1, ENC_BIG_ENDIAN);
358 break;
359 case 2: /* colour type 0, 4 */
360 proto_tree_add_item(tree, &hfi_png_bkgd_greyscale, tvb, 0, 2, ENC_BIG_ENDIAN);
361 break;
362 case 6: /* colour type 2, 6 */
363 proto_tree_add_item(tree, &hfi_png_bkgd_red, tvb, 0, 2, ENC_BIG_ENDIAN);
364 proto_tree_add_item(tree, &hfi_png_bkgd_green, tvb, 2, 2, ENC_BIG_ENDIAN);
365 proto_tree_add_item(tree, &hfi_png_bkgd_blue, tvb, 4, 2, ENC_BIG_ENDIAN);
366 break;
367 }
368 }
369
370 static void
dissect_png_chrm(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree)371 dissect_png_chrm(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
372 {
373 float wx, wy, rx, ry, gx, gy, bx, by;
374 gint offset = 0;
375
376 wx = tvb_get_ntohl(tvb, offset) / 100000.0f;
377 proto_tree_add_float(tree, &hfi_png_chrm_white_x,
378 tvb, offset, 4, wx);
379 offset += 4;
380
381 wy = tvb_get_ntohl(tvb, offset) / 100000.0f;
382 proto_tree_add_float(tree, &hfi_png_chrm_white_y,
383 tvb, offset, 4, wy);
384 offset += 4;
385
386 rx = tvb_get_ntohl(tvb, offset) / 100000.0f;
387 proto_tree_add_float(tree, &hfi_png_chrm_red_x,
388 tvb, offset, 4, rx);
389 offset += 4;
390
391 ry = tvb_get_ntohl(tvb, offset) / 100000.0f;
392 proto_tree_add_float(tree, &hfi_png_chrm_red_y,
393 tvb, offset, 4, ry);
394 offset += 4;
395
396 gx = tvb_get_ntohl(tvb, offset) / 100000.0f;
397 proto_tree_add_float(tree, &hfi_png_chrm_green_x,
398 tvb, offset, 4, gx);
399 offset += 4;
400
401 gy = tvb_get_ntohl(tvb, offset) / 100000.0f;
402 proto_tree_add_float(tree, &hfi_png_chrm_green_y,
403 tvb, offset, 4, gy);
404 offset += 4;
405
406 bx = tvb_get_ntohl(tvb, offset) / 100000.0f;
407 proto_tree_add_float(tree, &hfi_png_chrm_blue_x,
408 tvb, offset, 4, bx);
409 offset += 4;
410
411 by = tvb_get_ntohl(tvb, offset) / 100000.0f;
412 proto_tree_add_float(tree, &hfi_png_chrm_blue_y,
413 tvb, offset, 4, by);
414 }
415
416 static void
dissect_png_gama(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree)417 dissect_png_gama(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
418 {
419 float gamma;
420
421 gamma = tvb_get_ntohl(tvb, 0) / 100000.0f;
422 proto_tree_add_float(tree, &hfi_png_gama_gamma,
423 tvb, 0, 4, gamma);
424 }
425
426 static gint
dissect_png(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data _U_)427 dissect_png(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data _U_)
428 {
429 proto_tree *tree;
430 proto_item *ti;
431 gint offset=0;
432 /* http://libpng.org/pub/png/spec/1.2/PNG-Structure.html#PNG-file-signature */
433 static const guint8 magic[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
434
435 if (tvb_captured_length(tvb) < 20)
436 return 0;
437 if (tvb_memeql(tvb, 0, magic, sizeof(magic)) != 0)
438 return 0;
439
440 col_append_str(pinfo->cinfo, COL_INFO, " (PNG)");
441
442 ti=proto_tree_add_item(parent_tree, hfi_png, tvb, offset, -1, ENC_NA);
443 tree=proto_item_add_subtree(ti, ett_png);
444
445 proto_tree_add_item(tree, &hfi_png_signature, tvb, offset, 8, ENC_NA);
446 offset+=8;
447
448 while(tvb_reported_length_remaining(tvb, offset) > 0){
449 guint32 len_field;
450 proto_item *len_it;
451 proto_tree *chunk_tree;
452 guint32 type;
453 guint8 *type_str;
454 tvbuff_t *chunk_tvb;
455
456 len_field = tvb_get_ntohl(tvb, offset);
457
458 type = tvb_get_ntohl(tvb, offset+4);
459 type_str = tvb_get_string_enc(pinfo->pool,
460 tvb, offset+4, 4, ENC_ASCII|ENC_NA);
461
462 /* 4 byte len field, 4 byte chunk type, 4 byte CRC */
463 chunk_tree = proto_tree_add_subtree_format(tree, tvb, offset, 4+4+len_field+4, ett_png_chunk, NULL,
464 "%s (%s)", val_to_str_const(type, chunk_types, "unknown"), type_str);
465
466 len_it = proto_tree_add_item(chunk_tree, &hfi_png_chunk_len,
467 tvb, offset, 4, ENC_BIG_ENDIAN);
468 offset+=4;
469 if (len_field > G_MAXINT) {
470 expert_add_info(pinfo, len_it, &ei_png_chunk_too_large);
471 return offset;
472 }
473
474 proto_tree_add_item(chunk_tree, &hfi_png_chunk_type_str,
475 tvb, offset, 4, ENC_ASCII|ENC_NA);
476
477 proto_tree_add_item(chunk_tree, &hfi_png_chunk_flag_anc, tvb, offset, 4, ENC_BIG_ENDIAN);
478 proto_tree_add_item(chunk_tree, &hfi_png_chunk_flag_priv, tvb, offset, 4, ENC_BIG_ENDIAN);
479 proto_tree_add_item(chunk_tree, &hfi_png_chunk_flag_stc, tvb, offset, 4, ENC_BIG_ENDIAN);
480 offset+=4;
481
482 chunk_tvb=tvb_new_subset_length(tvb, offset, len_field);
483 switch (type) {
484 case CHUNK_TYPE_IHDR:
485 dissect_png_ihdr(chunk_tvb, pinfo, chunk_tree);
486 break;
487 case CHUNK_TYPE_bKGD:
488 dissect_png_bkgd(chunk_tvb, pinfo, chunk_tree);
489 break;
490 case CHUNK_TYPE_cHRM:
491 dissect_png_chrm(chunk_tvb, pinfo, chunk_tree);
492 break;
493 case CHUNK_TYPE_gAMA:
494 dissect_png_gama(chunk_tvb, pinfo, chunk_tree);
495 break;
496 case CHUNK_TYPE_pHYs:
497 dissect_png_phys(chunk_tvb, pinfo, chunk_tree);
498 break;
499 case CHUNK_TYPE_sRGB:
500 dissect_png_srgb(chunk_tvb, pinfo, chunk_tree);
501 break;
502 case CHUNK_TYPE_tEXt:
503 dissect_png_text(chunk_tvb, pinfo, chunk_tree);
504 break;
505 case CHUNK_TYPE_tIME:
506 dissect_png_time(chunk_tvb, pinfo, chunk_tree);
507 break;
508 default:
509 if (len_field>0) {
510 proto_tree_add_item(chunk_tree, &hfi_png_chunk_data,
511 tvb, offset, len_field, ENC_NA);
512 }
513 break;
514 }
515 offset += len_field;
516
517 proto_tree_add_item(chunk_tree, &hfi_png_chunk_crc, tvb, offset, 4, ENC_BIG_ENDIAN);
518 offset+=4;
519 }
520 return offset;
521 }
522
523 void
proto_register_png(void)524 proto_register_png(void)
525 {
526 #ifndef HAVE_HFI_SECTION_INIT
527 static header_field_info *hfi[] =
528 {
529 &hfi_png_signature,
530 &hfi_png_chunk_type_str,
531 &hfi_png_chunk_data,
532 &hfi_png_chunk_len,
533 &hfi_png_chunk_crc,
534 &hfi_png_chunk_flag_anc,
535 &hfi_png_chunk_flag_priv,
536 &hfi_png_chunk_flag_stc,
537 &hfi_png_ihdr_width,
538 &hfi_png_ihdr_height,
539 &hfi_png_ihdr_bitdepth,
540 &hfi_png_ihdr_colour_type,
541 &hfi_png_ihdr_compression_method,
542 &hfi_png_ihdr_filter_method,
543 &hfi_png_ihdr_interlace_method,
544 &hfi_png_srgb_intent,
545 &hfi_png_text_keyword,
546 &hfi_png_text_string,
547 &hfi_png_time_year,
548 &hfi_png_time_month,
549 &hfi_png_time_day,
550 &hfi_png_time_hour,
551 &hfi_png_time_minute,
552 &hfi_png_time_second,
553 &hfi_png_phys_horiz,
554 &hfi_png_phys_vert,
555 &hfi_png_phys_unit,
556 &hfi_png_bkgd_palette_index,
557 &hfi_png_bkgd_greyscale,
558 &hfi_png_bkgd_red,
559 &hfi_png_bkgd_green,
560 &hfi_png_bkgd_blue,
561 &hfi_png_chrm_white_x,
562 &hfi_png_chrm_white_y,
563 &hfi_png_chrm_red_x,
564 &hfi_png_chrm_red_y,
565 &hfi_png_chrm_green_x,
566 &hfi_png_chrm_green_y,
567 &hfi_png_chrm_blue_x,
568 &hfi_png_chrm_blue_y,
569 &hfi_png_gama_gamma
570 };
571 #endif
572
573 static gint *ett[] =
574 {
575 &ett_png,
576 &ett_png_chunk,
577 };
578
579 static ei_register_info ei[] = {
580 { &ei_png_chunk_too_large,
581 { "png.chunk_too_large", PI_PROTOCOL, PI_WARN,
582 "chunk size too large, dissection of this chunk is not supported", EXPFILL }}
583 };
584 expert_module_t *expert_png;
585
586 int proto_png;
587
588 proto_png = proto_register_protocol("Portable Network Graphics","PNG","png");
589 hfi_png = proto_registrar_get_nth(proto_png);
590
591 proto_register_fields(proto_png, hfi, array_length(hfi));
592 proto_register_subtree_array(ett, array_length(ett));
593
594 expert_png = expert_register_protocol(proto_png);
595 expert_register_field_array(expert_png, ei, array_length(ei));
596
597 png_handle = register_dissector("png", dissect_png, proto_png);
598 }
599
dissect_png_heur(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)600 static gboolean dissect_png_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
601 {
602 return dissect_png(tvb, pinfo, tree, NULL) > 0;
603 }
604
605 void
proto_reg_handoff_png(void)606 proto_reg_handoff_png(void)
607 {
608 dissector_add_string("media_type", "image/png", png_handle);
609 heur_dissector_add("http", dissect_png_heur, "PNG file in HTTP", "png_http", hfi_png->id, HEURISTIC_ENABLE);
610 heur_dissector_add("wtap_file", dissect_png_heur, "PNG file in HTTP", "png_wtap", hfi_png->id, HEURISTIC_ENABLE);
611 }
612
613 /*
614 * Editor modelines - https://www.wireshark.org/tools/modelines.html
615 *
616 * Local variables:
617 * c-basic-offset: 4
618 * tab-width: 8
619 * indent-tabs-mode: nil
620 * End:
621 *
622 * vi: set shiftwidth=4 tabstop=8 expandtab:
623 * :indentSize=4:tabSize=8:noTabs=true:
624 */
625