File Coverage

blib/lib/Parse/Win32Registry/Win95/Value.pm
Criterion Covered Total %
statement 94 97 96.9
branch 45 50 90.0
condition 5 8 62.5
subroutine 10 11 90.9
pod 0 4 0.0
total 154 170 90.5


line stmt bran cond sub pod time code
1             package Parse::Win32Registry::Win95::Value;
2              
3 13     13   93 use strict;
  13         33  
  13         419  
4 13     13   75 use warnings;
  13         27  
  13         357  
5              
6 13     13   65 use base qw(Parse::Win32Registry::Value);
  13         29  
  13         5497  
7              
8 13     13   95 use Carp;
  13         33  
  13         615  
9 13     13   77 use Encode;
  13         29  
  13         1273  
10 13     13   318 use Parse::Win32Registry::Base qw(:all);
  13         222  
  13         2624  
11              
12 13     13   103 use constant RGDB_VALUE_HEADER_LENGTH => 0xc;
  13         26  
  13         12028  
13              
14             sub new {
15 3190     3190 0 5201 my $class = shift;
16 3190         4740 my $regfile = shift;
17 3190         4382 my $offset = shift; # offset to RGDB value entry
18              
19 3190 50       6126 croak 'Missing registry file' if !defined $regfile;
20 3190 50       5551 croak 'Missing offset' if !defined $offset;
21              
22 3190         7620 my $fh = $regfile->get_filehandle;
23              
24             # RGDB Value Entry
25             # 0x00 dword = value type
26             # 0x04
27             # 0x08 word = value name length
28             # 0x0a word = value data length
29             # 0x0c = value name [for name length bytes]
30             # + value data [for data length bytes]
31             # Value type may just be a word, not a dword;
32             # following word always appears to be zero.
33              
34 3190         18319 sysseek($fh, $offset, 0);
35 3190         22799 my $bytes_read = sysread($fh, my $rgdb_value_entry,
36             RGDB_VALUE_HEADER_LENGTH);
37 3190 100       8390 if ($bytes_read != RGDB_VALUE_HEADER_LENGTH) {
38 1         6 warnf('Could not read RGDB value at 0x%x', $offset);
39 1         15 return;
40             }
41              
42 3189         10707 my ($type,
43             $name_length,
44             $data_length) = unpack('Vx4vv', $rgdb_value_entry);
45              
46 3189         19509 $bytes_read = sysread($fh, my $name, $name_length);
47 3189 100       8829 if ($bytes_read != $name_length) {
48 1         5 warnf('Could not read name for RGDB value at 0x%x', $offset);
49 1         29 return;
50             }
51 3188         9192 $name = decode($Parse::Win32Registry::Base::CODEPAGE, $name);
52              
53 3188         110692 $bytes_read = sysread($fh, my $data, $data_length);
54 3188 100       9052 if ($bytes_read != $data_length) {
55 1         5 warnf('Could not read data for RGDB value at 0x%x', $offset);
56 1         16 return;
57             }
58              
59 3187         5913 my $self = {};
60 3187         6972 $self->{_regfile} = $regfile;
61 3187         5545 $self->{_offset} = $offset;
62 3187         5644 $self->{_length} = RGDB_VALUE_HEADER_LENGTH + $name_length + $data_length;
63 3187         4947 $self->{_allocated} = 1;
64 3187         5206 $self->{_tag} = 'rgdb value';
65 3187         5120 $self->{_name} = $name;
66 3187         4613 $self->{_name_length} = $name_length;
67 3187         7412 $self->{_type} = $type;
68 3187         5211 $self->{_data} = $data;
69 3187         4779 $self->{_data_length} = $data_length;
70 3187         5558 bless $self, $class;
71              
72 3187         12068 return $self;
73             }
74              
75             sub get_data {
76 222     222 0 425 my $self = shift;
77              
78 222         536 my $type = $self->get_type;
79              
80 222         431 my $data = $self->{_data};
81 222 50       519 return if !defined $data; # actually, Win95 value data is always defined
82              
83             # apply decoding to appropriate data types
84 222 100 66     857 if ($type == REG_DWORD) {
    100          
    100          
    100          
85 80 100       174 if (length($data) == 4) {
86 65         182 $data = unpack('V', $data);
87             }
88             else {
89             # incorrect length for dword data
90 15         26 $data = undef;
91             }
92             }
93             elsif ($type == REG_DWORD_BIG_ENDIAN) {
94 32 100       69 if (length($data) == 4) {
95 20         61 $data = unpack('N', $data);
96             }
97             else {
98             # incorrect length for dword data
99 12         18 $data = undef;
100             }
101             }
102             elsif ($type == REG_SZ || $type == REG_EXPAND_SZ) {
103             # Snip off any terminating null.
104             # Typically, REG_SZ values will not have a terminating null,
105             # while REG_EXPAND_SZ values will have a terminating null
106 20 100       65 chop $data if substr($data, -1, 1) eq "\0";
107             }
108             elsif ($type == REG_MULTI_SZ) {
109             # Snip off any terminating nulls
110 78 100       245 chop $data if substr($data, -1, 1) eq "\0";
111 78 100       175 chop $data if substr($data, -1, 1) eq "\0";
112 78         226 my @multi_sz = split("\0", $data, -1);
113             # Make sure there is at least one empty string
114 78 100       187 @multi_sz = ('') if @multi_sz == 0;
115 78 100       701 return wantarray ? @multi_sz : join($", @multi_sz);
116             }
117              
118 144         761 return $data;
119             }
120              
121             sub as_regedit_export {
122 39     39 0 91 my $self = shift;
123 39   50     169 my $version = shift || 5;
124              
125 39         113 my $name = $self->get_name;
126 39 100       159 my $export = $name eq '' ? '@=' : '"' . $name . '"=';
127              
128 39         104 my $type = $self->get_type;
129              
130             # XXX
131             # if (!defined $self->{_data}) {
132             # $name = $name eq '' ? '@' : qq{"$name"};
133             # return qq{; $name=(invalid data)\n};
134             # }
135              
136 39 100 66     221 if ($type == REG_SZ) {
    100          
    100          
    100          
137 4         9 my $data = $self->get_data;
138 4 50       10 $data = '' if !defined($data);
139 4         14 $export .= '"' . $data . '"';
140 4         10 $export .= "\n";
141             }
142             elsif ($type == REG_BINARY) {
143 2         14 $export .= 'hex:';
144 2         17 $export .= format_octets($self->{_data}, length($export));
145             }
146             elsif ($type == REG_DWORD) {
147 12         32 my $data = $self->get_data;
148 12 100       69 $export .= defined($data)
149             ? sprintf("dword:%08x", $data)
150             : "dword:";
151 12         32 $export .= "\n";
152             }
153             elsif ($type == REG_EXPAND_SZ || $type == REG_MULTI_SZ) {
154             my $data = $version == 4
155             ? $self->{_data} # raw data
156 12 50       69 : encode("UCS-2LE", $self->{_data}); # ansi->unicode
157 12         3840 $export .= sprintf("hex(%x):", $type);
158 12         63 $export .= format_octets($data, length($export));
159             }
160             else {
161 9         50 $export .= sprintf("hex(%x):", $type);
162 9         51 $export .= format_octets($self->{_data}, length($export));
163             }
164 39         176 return $export;
165             }
166              
167             sub parse_info {
168 0     0 0   my $self = shift;
169              
170             my $info = sprintf '0x%x rgdb value len=0x%x "%s" type=%d data,len=0x%x',
171             $self->{_offset},
172             $self->{_length},
173             $self->{_name},
174             $self->{_type},
175 0           $self->{_data_length};
176 0           return $info;
177             }
178              
179             1;