File Coverage

blib/lib/Net/Tshark/Field.pm
Criterion Covered Total %
statement 15 115 13.0
branch 0 32 0.0
condition 0 12 0.0
subroutine 5 28 17.8
pod 7 9 77.7
total 27 196 13.7


line stmt bran cond sub pod time code
1             package Net::Tshark::Field;
2 1     1   3845 use strict;
  1         3  
  1         29  
3 1     1   4 use warnings;
  1         1  
  1         42  
4            
5             our $VERSION = '0.04';
6            
7 1     1   779 use List::MoreUtils qw(any all uniq after);
  1         1189  
  1         113  
8 1     1   8 use List::Util qw(reduce);
  1         3  
  1         151  
9            
10             use overload (
11             q("") => sub {
12 0     0     my $self = tied %{ $_[0] };
  0            
13 0           $self->{__value};
14             }
15 1     1   6 );
  1         2  
  1         10  
16            
17             sub new
18             {
19 0     0 0   my ($class, $field_data) = @_;
20 0 0         return if (!defined $field_data);
21            
22             # Extract the value, and child nodes of this field
23 0 0         my $value =
24             (defined $field_data->{show})
25             ? $field_data->{show}
26             : $field_data->{showname};
27 0 0         my @child_nodes =
28 0 0         (@{ $field_data->{field} || [] }, @{ $field_data->{proto} || [] });
  0            
29            
30             # If this node has no children, we can just return a scalar
31 0 0         return $value if (!@child_nodes);
32            
33             # If a field doesn't have a name, give it a name based on
34             # its showname or show attribute.
35 0           foreach (@child_nodes)
36             {
37 0 0 0       if (!defined $_->{name} || !length $_->{name})
38             {
39 0 0 0       $_->{name} =
    0          
40             defined $_->{showname} && length($_->{showname}) ? $_->{showname}
41             : defined $_->{show} ? $_->{show}
42             : q();
43             }
44             }
45            
46 0           my $data = {
47             show => $field_data->{show},
48             showname => $field_data->{showname},
49             name => $field_data->{name},
50             size => $field_data->{size},
51             value => $field_data->{value},
52             __value => $value,
53             __child_nodes => \@child_nodes,
54             };
55            
56             # Tie a new hash to this package so we can access parts of the parsed
57             # PDML using hash notation (e.g. $packet->{ip}). Note that the TIEHASH
58             # subroutine does the actual construction of the object.
59 0           my $self = {};
60 0           tie %{$self}, $class, $data;
  0            
61 0           return bless $self, $class;
62             }
63            
64             sub fields
65             {
66 0     0 1   my ($field) = @_;
67 0           my $self = tied %{$field};
  0            
68 0           return map { Net::Tshark::Field->new($_) } @{ $self->{__child_nodes} };
  0            
  0            
69             }
70            
71             sub show
72             {
73 0     0 1   my ($field) = @_;
74 0           my $self = tied %{$field};
  0            
75 0           return $self->{show};
76             }
77            
78             sub showname
79             {
80 0     0 1   my ($field) = @_;
81 0           my $self = tied %{$field};
  0            
82 0           return $self->{showname};
83             }
84            
85             sub name
86             {
87 0     0 1   my ($field) = @_;
88 0           my $self = tied %{$field};
  0            
89 0           return $self->{name};
90             }
91            
92             sub size
93             {
94 0     0 1   my ($field) = @_;
95 0           my $self = tied %{$field};
  0            
96 0           return $self->{size};
97             }
98            
99             sub value
100             {
101 0     0 1   my ($field) = @_;
102 0           my $self = tied %{$field};
  0            
103 0           return $self->{value};
104             }
105            
106             sub hash
107             {
108 0     0 1   my ($field) = @_;
109            
110 0           my %hash = %{$field};
  0            
111 0           while (my ($key, $value) = each %hash)
112             {
113 0 0         if (ref $hash{$key})
114             {
115 0           my $sub_hash = $hash{$key}->hash;
116 0           $hash{$key} = $sub_hash;
117             }
118             }
119            
120 0           return \%hash;
121             }
122            
123             sub TIEHASH
124             {
125 0     0     my ($class, $self) = @_;
126 0           return bless $self, $class;
127             }
128            
129             sub STORE
130 0     0     {
131            
132             # Do nothing. If someone tries to access a field that doesn't exist,
133             # Perl will try to create it via autovilification. We don't want to
134             # create anything, but we also don't want this to trigger any warnings.
135             }
136            
137             sub FETCH
138             {
139 0     0     my ($self, $key) = @_;
140 0           my @nodes = $self->__fields($key);
141            
142             # If nothing was found, do a deep search in the child nodes for a name match
143 0 0         if (!@nodes)
144             {
145 0           foreach my $child (@{ $self->{__child_nodes} })
  0            
146             {
147 0           push @nodes,
148 0 0         grep { $_->{name} =~ /^(?:.*\.)?$key$/i }
149 0 0         (@{ $child->{field} || [] }, @{ $child->{proto} || [] });
  0            
150             }
151             }
152            
153             # If all the matching fields are leaves, append all their values and
154             # return them as a constructed field
155 0 0 0 0     if (all { !defined $_->{field} && !defined $_->{proto} } @nodes)
  0            
156             {
157 0 0         my $show = join(q(),
158 0           map { (defined $_->{show}) ? $_->{show} : $_->{showname} } @nodes);
159 0           return Net::Tshark::Field->new({ show => $show });
160             }
161            
162             # Otherwise, return the first matching node
163 0           return Net::Tshark::Field->new($nodes[0]);
164             }
165            
166             sub EXISTS
167             {
168 0     0     my ($self, $key) = @_;
169 0     0     return any { $_->{name} =~ /^(?:.*\.)?$key$/i } @{ $self->{__child_nodes} };
  0            
  0            
170             }
171            
172             sub DEFINED
173             {
174 0     0 0   return EXISTS(@_);
175             }
176            
177             sub CLEAR
178             {
179 0     0     warn 'You cannot clear a ' . __PACKAGE__ . ' object';
180 0           return;
181             }
182            
183             sub DELETE
184             {
185 0     0     warn 'You cannot delete from a ' . __PACKAGE__ . ' object';
186 0           return;
187             }
188            
189             sub FIRSTKEY
190             {
191 0     0     my ($self) = @_;
192 0           return (@{ $self->{__child_nodes} })[0]->{name};
  0            
193             }
194            
195             sub NEXTKEY
196             {
197 0     0     my ($self, $last_key) = @_;
198            
199             # Get a set of all the names of the child nodes, with no repeats
200 0           my @keys = uniq(map { $_->{name} } @{ $self->{__child_nodes} });
  0            
  0            
201 0     0     return (after { $_ eq $last_key } (@keys))[0];
  0            
202             }
203            
204             sub __fields
205             {
206 0     0     my ($self, $key) = @_;
207            
208             # Message bodies are named differently in different versions of Wireshark
209 0 0 0       if ($key eq 'Message body' || $key eq 'msg_body')
210             {
211 0           $key = qr/Message body|msg_body/;
212             }
213            
214             # Find all the fields with a name that matches $key.
215 0           my @matching_nodes =
216 0           grep { $_->{name} =~ /^(?:.*\.)?$key$/i } @{ $self->{__child_nodes} };
  0            
217            
218             # Choose the shortest matching field name
219 0 0   0     my $shortestName = reduce { length($a) < length($b) ? $a : $b }
220 0           map { $_->{name} } @matching_nodes;
  0            
221            
222             # If there are more than one matching field, choose the
223             # field or protocol with the shortest name.
224 0           my @nodes = grep { $_->{name} eq $shortestName } (@matching_nodes);
  0            
225            
226 0           return @nodes;
227             }
228            
229             1;
230            
231             __END__