File Coverage

blib/lib/Parse/Win32Registry/Key.pm
Criterion Covered Total %
statement 105 133 78.9
branch 26 48 54.1
condition 4 9 44.4
subroutine 19 24 79.1
pod 0 13 0.0
total 154 227 67.8


line stmt bran cond sub pod time code
1             package Parse::Win32Registry::Key;
2              
3 13     13   111 use strict;
  13         26  
  13         385  
4 13     13   119 use warnings;
  13         28  
  13         386  
5              
6 13     13   67 use base qw(Parse::Win32Registry::Entry);
  13         25  
  13         6197  
7              
8 13     13   100 use Carp;
  13         29  
  13         18367  
9              
10             sub get_name {
11 302     302 0 9778 my $self = shift;
12              
13             # the root key of a windows 95 registry has no defined name
14             # but this should be set to '' when created
15 302         1039 return $self->{_name};
16             }
17              
18             sub get_path {
19 337     337 0 77615 my $self = shift;
20              
21 337         1533 return $self->{_key_path};
22             }
23              
24             sub _look_up_subkey {
25 117     117   182 my $self = shift;
26 117         197 my $subkey_name = shift;
27              
28 117 50       267 croak 'Missing subkey name' if !defined $subkey_name;
29              
30 117         312 foreach my $subkey ($self->get_list_of_subkeys) {
31 295 100   1   28404 if (uc $subkey_name eq uc $subkey->{_name}) {
  1         938  
  1         17  
  1         15  
32 117         588 return $subkey;
33             }
34             }
35 0         0 return;
36             }
37              
38             sub get_subkey {
39 89     89 0 35433 my $self = shift;
40 89         158 my $subkey_path = shift;
41              
42             # check for definedness in case key name is '' or '0'
43 89 100       402 croak "Usage: get_subkey('key name')" if !defined $subkey_path;
44              
45 88         174 my $key = $self;
46              
47             # Current path component separator is '\' to match that used in Windows.
48             # split returns nothing if it is given an empty string,
49             # and without a limit of -1 drops trailing empty fields.
50             # The following returns a list with a single zero-length string ("")
51             # for an empty string, as split(/\\/, $subkey_path, -1) returns (),
52             # an empty list.
53 88 100       377 my @path_components = index($subkey_path, "\\") == -1
54             ? ($subkey_path)
55             : split(/\\/, $subkey_path, -1);
56              
57 88         177 my %offsets_seen = ();
58 88         261 $offsets_seen{$key->get_offset} = undef;
59              
60 88         212 foreach my $subkey_name (@path_components) {
61 117 50       269 if (my $subkey = $key->_look_up_subkey($subkey_name)) {
62 117 50       386 if (exists $offsets_seen{$subkey->get_offset}) {
63 0         0 return; # found loop
64             }
65 117         263 $key = $subkey;
66 117         287 $offsets_seen{$key->get_offset} = undef;
67             }
68             else { # subkey name not found, abort look up
69 0         0 return;
70             }
71             }
72 88         368 return $key;
73             }
74              
75             sub get_value {
76 185     185 0 55405 my $self = shift;
77 185         303 my $value_name = shift;
78              
79             # check for definedness in case value name is '' or '0'
80 185 100       537 croak "Usage: get_value('value name')" if !defined $value_name;
81              
82 184         438 foreach my $value ($self->get_list_of_values) {
83 4594 100       9978 if (uc $value_name eq uc $value->{_name}) {
84 184         4096 return $value;
85             }
86             }
87 0         0 return undef;
88             }
89              
90             sub print_summary {
91 0     0 0 0 my $self = shift;
92              
93 0         0 print $self->as_string, "\n";
94             }
95              
96             sub as_regedit_export {
97 37     37 0 83 my $self = shift;
98              
99 37         242 return "[" . $self->{_key_path} . "]\n";
100             }
101              
102             sub regenerate_path {
103 59     59 0 111 my $self = shift;
104              
105             # ascend to the root
106 59         95 my $key = $self;
107 59         171 my @key_names = ($key->get_name);
108              
109 59         126 my %offsets_seen = ();
110 59         161 while (!$key->is_root) {
111 104         279 $offsets_seen{$key->get_offset}++;
112 104         278 $key = $key->get_parent;
113 104 50       246 if (!defined $key) { # found an undefined parent key
114 0         0 unshift @key_names, '(Invalid Parent Key)';
115 0         0 last;
116             }
117 104 50       306 if (exists $offsets_seen{$key->get_offset}) { # found loop
118 0         0 unshift @key_names, '(Invalid Parent Key)';
119 0         0 last;
120             }
121 104         267 unshift @key_names, $key->get_name;
122             }
123              
124 59         192 my $key_path = join('\\', @key_names);
125 59         119 $self->{_key_path} = $key_path;
126 59         356 return $key_path;
127             }
128              
129             sub get_value_data {
130 92     92 0 197 my $self = shift;
131 92         206 my $value_name = shift;
132              
133 92 50       260 croak "Usage: get_value_data('value name')" if !defined $value_name;
134              
135 92 50       249 if (my $value = $self->get_value($value_name)) {
136 92         321 return $value->get_data;
137             }
138 0         0 return;
139             }
140              
141             sub get_mru_list_of_values {
142 0     0 0 0 my $self = shift;
143              
144 0         0 my @values = ();
145              
146 0 0       0 if (my $mrulist = $self->get_value('MRUList')) {
    0          
147 0         0 foreach my $ch (split(//, $mrulist->get_data)) {
148 0 0       0 if (my $value = $self->get_value($ch)) {
149 0         0 push @values, $value;
150             }
151             }
152             }
153             elsif (my $mrulistex = $self->get_value('MRUListEx')) {
154 0         0 foreach my $item (unpack('V*', $mrulistex->get_data)) {
155 0 0       0 last if $item == 0xffffffff;
156 0 0       0 if (my $value = $self->get_value($item)) {
157 0         0 push @values, $value;
158             }
159             }
160             }
161 0         0 return @values;
162             }
163              
164             sub get_list_of_subkeys {
165 227     227 0 396 my $self = shift;
166              
167 227         644 my $subkey_iter = $self->get_subkey_iterator;
168 227         443 my @subkeys;
169 227         511 while (my $subkey = $subkey_iter->()) {
170 556         1497 push @subkeys, $subkey;
171             }
172 227         1416 return @subkeys;
173             }
174              
175             sub get_list_of_values {
176 291     291 0 21038 my $self = shift;
177              
178 291         885 my $value_iter = $self->get_value_iterator;
179 291         505 my @values;
180 291         683 while (my $value = $value_iter->()) {
181 9262         24128 push @values, $value;
182             }
183 291         2576 return @values;
184             }
185              
186             sub get_subtree_iterator {
187 6     6 0 1414 my $self = shift;
188              
189 6         20 my @start_keys = ($self);
190             push my (@subkey_iters), Parse::Win32Registry::Iterator->new(sub {
191 12     12   27 return shift @start_keys;
192 6         48 });
193 6         16 my $value_iter;
194             my $key; # used to remember key while iterating values
195              
196             return Parse::Win32Registry::Iterator->new(sub {
197 66 100 100 66   334 if (defined $value_iter && wantarray) {
198 40         113 my $value = $value_iter->();
199 40 100       102 if (defined $value) {
200 26         108 return ($key, $value);
201             }
202             # $value_iter finished, so fetch a new one
203             # from the (current) $subkey_iter[-1]
204             }
205 40         101 while (@subkey_iters > 0) {
206 74         181 $key = $subkey_iters[-1]->(); # depth-first
207 74 100       170 if (defined $key) {
208 34         107 push @subkey_iters, $key->get_subkey_iterator;
209 34         106 $value_iter = $key->get_value_iterator;
210 34         119 return $key;
211             }
212 40         192 pop @subkey_iters; # $subkey_iter finished, so remove it
213             }
214 6         19 return;
215 6         34 });
216             }
217              
218             sub walk {
219 14     14 0 132 my $self = shift;
220 14         28 my $key_enter_func = shift;
221 14         19 my $value_func = shift;
222 14         36 my $key_leave_func = shift;
223              
224 14 0 33     41 if (!defined $key_enter_func &&
      0        
225             !defined $value_func &&
226             !defined $key_leave_func) {
227 0     0   0 $key_enter_func = sub { print "+ ", $_[0]->get_path, "\n"; };
  0         0  
228 0     0   0 $value_func = sub { print " '", $_[0]->get_name, "'\n"; };
  0         0  
229 0     0   0 $key_leave_func = sub { print "- ", $_[0]->get_path, "\n"; };
  0         0  
230             }
231              
232 14 50       62 $key_enter_func->($self) if ref $key_enter_func eq 'CODE';
233              
234 14         9356 foreach my $value ($self->get_list_of_values) {
235 26 50       8492 $value_func->($value) if ref $value_func eq 'CODE';
236             }
237              
238 14         8040 foreach my $subkey ($self->get_list_of_subkeys) {
239 12         3685 $subkey->walk($key_enter_func, $value_func, $key_leave_func);
240             }
241              
242 14 50       3786 $key_leave_func->($self) if ref $key_leave_func eq 'CODE';
243             }
244              
245             1;