wireshark/epan/dissectors/packet-image-png.c
Guy Harris 83fc9d5e09 Constify a bunch of stuff, to squelch -Wwrite-strings warnings.
epan/dissectors/packet-ncp2222.inc is a bit hard to fix, so we're not
ready to enable that warning by default yet.

Throw in some casts to handle GLib routines that take arbitrary
non-const pointers (they can later return the pointers, and some
callers might want to modify or free up those pointers in cases where
they're known to be writable or allocated).

Use ep_tvb_memdup() rather than a combination of ep_alloc() and
tvb_memcpy().

Clean up some indentation.

svn path=/trunk/; revision=25601
2008-06-25 09:12:35 +00:00

428 lines
13 KiB
C

/* packet-image-png.c
*
* Routines for PNG (Portable Network Graphics) image file dissection
*
* $Id$
*
* Copyright 2006 Ronnie Sahlberg
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* See http://www.w3.org/TR/PNG for specification
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <glib.h>
#include <epan/packet.h>
static int proto_png = -1;
static int hf_png_signature = -1;
static int hf_png_chunk_data = -1;
static int hf_png_chunk_type = -1;
static int hf_png_chunk_len = -1;
static int hf_png_chunk_crc = -1;
static int hf_png_chunk_flag_anc = -1;
static int hf_png_chunk_flag_priv = -1;
static int hf_png_chunk_flag_stc = -1;
static int hf_png_ihdr_width = -1;
static int hf_png_ihdr_height = -1;
static int hf_png_ihdr_bitdepth = -1;
static int hf_png_ihdr_colour_type = -1;
static int hf_png_ihdr_compression_method = -1;
static int hf_png_ihdr_filter_method = -1;
static int hf_png_ihdr_interlace_method = -1;
static int hf_png_text_keyword = -1;
static int hf_png_text_string = -1;
static int hf_png_time_year = -1;
static int hf_png_time_month = -1;
static int hf_png_time_day = -1;
static int hf_png_time_hour = -1;
static int hf_png_time_minute = -1;
static int hf_png_time_second = -1;
static int hf_png_phys_horiz = -1;
static int hf_png_phys_vert = -1;
static int hf_png_phys_unit = -1;
static int hf_png_bkgd_palette_index = -1;
static int hf_png_bkgd_greyscale = -1;
static int hf_png_bkgd_red = -1;
static int hf_png_bkgd_green = -1;
static int hf_png_bkgd_blue = -1;
static gint ett_png = -1;
static gint ett_png_chunk = -1;
static gint ett_png_chunk_item = -1;
static const value_string colour_type_vals[] = {
{ 0, "Greyscale"},
{ 2, "Truecolour"},
{ 3, "Indexed-colour"},
{ 4, "Greyscale with alpha"},
{ 6, "Truecolour with alpha"},
{ 0, NULL }
};
static const value_string compression_method_vals[] = {
{ 0, "Deflate"},
{ 0, NULL }
};
static const value_string filter_method_vals[] = {
{ 0, "Adaptive"},
{ 0, NULL }
};
static const value_string interlace_method_vals[] = {
{ 0, "No interlace"},
{ 1, "Adam7"},
{ 0, NULL }
};
static void
dissect_png_ihdr(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
int offset=0;
proto_tree_add_item(tree, hf_png_ihdr_width, tvb, offset, 4, FALSE);
offset+=4;
proto_tree_add_item(tree, hf_png_ihdr_height, tvb, offset, 4, FALSE);
offset+=4;
proto_tree_add_item(tree, hf_png_ihdr_bitdepth, tvb, offset, 1, FALSE);
offset+=1;
proto_tree_add_item(tree, hf_png_ihdr_colour_type, tvb, offset, 1, FALSE);
offset+=1;
proto_tree_add_item(tree, hf_png_ihdr_compression_method, tvb, offset, 1, FALSE);
offset+=1;
proto_tree_add_item(tree, hf_png_ihdr_filter_method, tvb, offset, 1, FALSE);
offset+=1;
proto_tree_add_item(tree, hf_png_ihdr_interlace_method, tvb, offset, 1, FALSE);
offset+=1;
return;
}
static void
dissect_png_text(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
int offset=1;
/* find the null that separates keyword and text string */
while(1){
if(!tvb_get_guint8(tvb, offset)){
break;
}
offset++;
}
proto_tree_add_item(tree, hf_png_text_keyword, tvb, 0, offset, FALSE);
offset++;
proto_tree_add_item(tree, hf_png_text_string, tvb, offset, tvb_length_remaining(tvb, offset), FALSE);
}
static void
dissect_png_time(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
proto_tree_add_item(tree, hf_png_time_year, tvb, 0, 2, FALSE);
proto_tree_add_item(tree, hf_png_time_month, tvb, 2, 1, FALSE);
proto_tree_add_item(tree, hf_png_time_day, tvb, 3, 1, FALSE);
proto_tree_add_item(tree, hf_png_time_hour, tvb, 4, 1, FALSE);
proto_tree_add_item(tree, hf_png_time_minute, tvb, 5, 1, FALSE);
proto_tree_add_item(tree, hf_png_time_second, tvb, 6, 1, FALSE);
}
static const value_string phys_unit_vals[] = {
{ 0, "Unit is unknown"},
{ 1, "Unit is METRE"},
{ 0, NULL }
};
static void
dissect_png_phys(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
proto_tree_add_item(tree, hf_png_phys_horiz, tvb, 0, 4, FALSE);
proto_tree_add_item(tree, hf_png_phys_vert, tvb, 4, 4, FALSE);
proto_tree_add_item(tree, hf_png_phys_unit, tvb, 8, 1, FALSE);
}
static void
dissect_png_bkgd(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
{
switch(tvb_reported_length(tvb)){
case 1: /* colour type 3 */
proto_tree_add_item(tree, hf_png_bkgd_palette_index, tvb, 0, 1, FALSE);
break;
case 2: /* colour type 0, 4 */
proto_tree_add_item(tree, hf_png_bkgd_greyscale, tvb, 0, 2, FALSE);
break;
case 6: /* colour type 2, 6 */
proto_tree_add_item(tree, hf_png_bkgd_red, tvb, 0, 2, FALSE);
proto_tree_add_item(tree, hf_png_bkgd_green, tvb, 2, 2, FALSE);
proto_tree_add_item(tree, hf_png_bkgd_blue, tvb, 4, 2, FALSE);
break;
}
}
typedef struct _chunk_dissector_t {
guint32 type;
const char *name;
void (*dissector)(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
} chunk_dissector_t;
static chunk_dissector_t chunk_table[] = {
{ 0x49484452, "Image Header", dissect_png_ihdr }, /* IHDR */
{ 0x624b4744, "Background colour", dissect_png_bkgd }, /* bKGD */
{ 0x70485973, "Physical pixel dimensions",
dissect_png_phys }, /* pHYs */
{ 0x74455874, "Textual data", dissect_png_text }, /* tEXt */
{ 0x74494d45, "Image last-modification time",
dissect_png_time }, /* tIME */
{ 0x49454e44, "Image Trailer", NULL }, /* IEND */
{ 0, NULL, NULL }
};
static const true_false_string png_chunk_anc = {
"This is an ANCILLARY chunk",
"This is a CRITICAL chunk"
};
static const true_false_string png_chunk_priv = {
"This is a PRIVATE chunk",
"This is a PUBLIC chunk"
};
static const true_false_string png_chunk_stc = {
"This chunk is SAFE TO COPY",
"This chunk is NOT safe to copy"
};
static void
dissect_png(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
{
proto_tree *tree = NULL;
proto_item *ti;
int offset=0;
if (check_col(pinfo->cinfo, COL_INFO))
col_append_str(pinfo->cinfo, COL_INFO, " (PNG)");
if(parent_tree){
ti=proto_tree_add_item(parent_tree, proto_png, tvb, offset, -1, FALSE);
tree=proto_item_add_subtree(ti, ett_png);
}
proto_tree_add_item(tree, hf_png_signature, tvb, offset, 8, FALSE);
offset+=8;
while(tvb_reported_length_remaining(tvb, offset)){
proto_tree *chunk_tree=NULL;
proto_item *it=NULL;
guint32 len, type;
chunk_dissector_t *cd;
char str[5];
len=tvb_get_ntohl(tvb, offset);
type=tvb_get_ntohl(tvb, offset+4);
str[0]=tvb_get_guint8(tvb, offset+4);
str[1]=tvb_get_guint8(tvb, offset+5);
str[2]=tvb_get_guint8(tvb, offset+6);
str[3]=tvb_get_guint8(tvb, offset+7);
str[4]=0;
if(tree){
it=proto_tree_add_text(tree, tvb, offset, offset+8+len+4, "%s", str);
chunk_tree=proto_item_add_subtree(it, ett_png_chunk);
}
proto_tree_add_item(chunk_tree, hf_png_chunk_len, tvb, offset, 4, FALSE);
offset+=4;
it=proto_tree_add_item(chunk_tree, hf_png_chunk_type, tvb, offset, 4, FALSE);
proto_tree_add_item(chunk_tree, hf_png_chunk_flag_anc, tvb, offset, 4, FALSE);
proto_tree_add_item(chunk_tree, hf_png_chunk_flag_priv, tvb, offset, 4, FALSE);
proto_tree_add_item(chunk_tree, hf_png_chunk_flag_stc, tvb, offset, 4, FALSE);
offset+=4;
if (len >= 1000000000)
THROW(ReportedBoundsError);
cd=&chunk_table[0];
while(1){
if(cd->type==0){
cd=NULL;
break;
}
if(cd->type==type){
break;
}
cd++;
}
if(chunk_tree){
proto_item_append_text(chunk_tree, " %s", cd?cd->name:"(dont know how to dissect this)");
}
if(!cd){
proto_tree_add_item(chunk_tree, hf_png_chunk_data, tvb, offset, len, FALSE);
} else {
if(cd->dissector){
tvbuff_t *next_tvb;
proto_tree *cti=NULL;
next_tvb=tvb_new_subset(tvb, offset, MIN(tvb_length_remaining(tvb, offset), (int)len), len);
if(it){
cti=proto_item_add_subtree(it, ett_png_chunk_item);
}
cd->dissector(next_tvb, pinfo, cti);
}
}
offset+=len;
proto_tree_add_item(chunk_tree, hf_png_chunk_crc, tvb, offset, 4, FALSE);
offset+=4;
}
}
void
proto_register_png(void)
{
static hf_register_info hf[] =
{
{ &hf_png_signature, {
"PNG Signature", "png.signature", FT_BYTES, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_chunk_type, {
"Chunk", "png.chunk.type", FT_STRING, BASE_NONE,
NULL, 0, "", HFILL }},
{ &hf_png_chunk_data, {
"Data", "png.chunk.data", FT_NONE, BASE_NONE,
NULL, 0, "", HFILL }},
{ &hf_png_chunk_len, {
"Len", "png.chunk.len", FT_UINT32, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_chunk_crc, {
"CRC", "png.chunk.crc", FT_UINT32, BASE_HEX,
NULL, 0, "", HFILL }},
{ &hf_png_chunk_flag_anc, {
"Ancillary", "png.chunk.flag.ancillary", FT_BOOLEAN, 32,
TFS(&png_chunk_anc), 0x20000000, "", HFILL }},
{ &hf_png_chunk_flag_priv, {
"Private", "png.chunk.flag.private", FT_BOOLEAN, 32,
TFS(&png_chunk_priv), 0x00200000, "", HFILL }},
{ &hf_png_chunk_flag_stc, {
"Safe To Copy", "png.chunk.flag.stc", FT_BOOLEAN, 32,
TFS(&png_chunk_stc), 0x00000020, "", HFILL }},
{ &hf_png_ihdr_width, {
"Width", "png.ihdr.width", FT_UINT32, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_ihdr_height, {
"Height", "png.ihdr.height", FT_UINT32, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_ihdr_bitdepth, {
"Bit Depth", "png.ihdr.bitdepth", FT_UINT8, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_ihdr_colour_type, {
"Colour Type", "png.ihdr.colour_type", FT_UINT8, BASE_DEC,
VALS(colour_type_vals), 0, "", HFILL }},
{ &hf_png_ihdr_compression_method, {
"Compression Method", "png.ihdr.compression_method", FT_UINT8, BASE_DEC,
VALS(compression_method_vals), 0, "", HFILL }},
{ &hf_png_ihdr_filter_method, {
"Filter Method", "png.ihdr.filter_method", FT_UINT8, BASE_DEC,
VALS(filter_method_vals), 0, "", HFILL }},
{ &hf_png_ihdr_interlace_method, {
"Interlace Method", "png.ihdr.interlace_method", FT_UINT8, BASE_DEC,
VALS(interlace_method_vals), 0, "", HFILL }},
{ &hf_png_text_keyword, {
"Keyword", "png.text.keyword", FT_STRING, BASE_NONE,
NULL, 0, "", HFILL }},
{ &hf_png_text_string, {
"String", "png.text.string", FT_STRING, BASE_NONE,
NULL, 0, "", HFILL }},
{ &hf_png_time_year, {
"Year", "png.time.year", FT_UINT16, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_time_month, {
"Month", "png.time.month", FT_UINT8, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_time_day, {
"Day", "png.time.day", FT_UINT8, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_time_hour, {
"Hour", "png.time.hour", FT_UINT8, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_time_minute, {
"Minute", "png.time.minute", FT_UINT8, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_time_second, {
"Second", "png.time.second", FT_UINT8, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_phys_horiz, {
"Horizontal pixels per unit", "png.phys.horiz", FT_UINT32, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_phys_vert, {
"Vertical pixels per unit", "png.phys.vert", FT_UINT32, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_phys_unit, {
"Unit", "png.phys.unit", FT_UINT8, BASE_DEC,
VALS(phys_unit_vals), 0, "", HFILL }},
{ &hf_png_bkgd_palette_index, {
"Palette Index", "png.bkgd.palette_index", FT_UINT8, BASE_DEC,
NULL, 0, "", HFILL }},
{ &hf_png_bkgd_greyscale, {
"Greyscale", "png.bkgd.greyscale", FT_UINT16, BASE_HEX,
NULL, 0, "", HFILL }},
{ &hf_png_bkgd_red, {
"Red", "png.bkgd.red", FT_UINT16, BASE_HEX,
NULL, 0, "", HFILL }},
{ &hf_png_bkgd_green, {
"Green", "png.bkgd.green", FT_UINT16, BASE_HEX,
NULL, 0, "", HFILL }},
{ &hf_png_bkgd_blue, {
"Blue", "png.bkgd.blue", FT_UINT16, BASE_HEX,
NULL, 0, "", HFILL }},
};
static gint *ett[] =
{
&ett_png,
&ett_png_chunk,
&ett_png_chunk_item,
};
proto_png = proto_register_protocol("Portable Network Graphics","PNG","png");
proto_register_field_array(proto_png, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_png(void)
{
dissector_handle_t png_handle;
png_handle = create_dissector_handle(dissect_png, proto_png);
dissector_add_string("media_type", "image/png", png_handle);
}