File Coverage

blib/lib/Palm/FieldPack.pm
Criterion Covered Total %
statement 9 89 10.1
branch 0 62 0.0
condition 0 15 0.0
subroutine 3 17 17.6
pod 0 12 0.0
total 12 195 6.1


line stmt bran cond sub pod time code
1             #
2             # Author : Maxime Soulé
3             # Created On : Sun Aug 29 23:17:21 2004
4             # Last Modified By: Maxime Soule
5             # Last Modified On: Mon May 3 15:02:20 2010
6             # Update Count : 4
7             #
8             # Copyright (C) 2005, Maxime Soulé
9             # You may distribute this file under the terms of the Artistic
10             # License, as specified in the README file.
11             #
12              
13             package Palm::FieldPack;
14              
15 2     2   46748 use Exporter;
  2         6  
  2         110  
16              
17 2     2   13 use base qw(Exporter);
  2         5  
  2         601  
18              
19             our @EXPORT = qw(pack_fields_to_UInt8 unpack_UInt8_to_fields
20             pack_fields_to_UInt16 unpack_UInt16_to_fields
21             pack_fields_to_UInt32 unpack_UInt32_to_fields
22             pack_DateType unpack_DateType
23             pack_TimeType unpack_TimeType
24             pack_double unpack_double);
25              
26             our $VERSION = '1.0';
27              
28              
29             my $big_endian;
30             BEGIN
31             {
32 2     2   5 if (length(pack('d', 0)) != 8)
33             {
34             die "Can't manage double values in this database, abort.\n";
35             }
36            
37 2         4 if (pack('I', 0x12345678) eq pack('N', 0x12345678))
38             {
39             $big_endian = 1;
40             }
41             elsif (pack('I', 0x12345678) eq pack('V', 0x12345678))
42             {
43 2         2839 $big_endian = 0;
44             }
45             else
46             {
47             die "Can't guess indianess of this host, abort\n";
48             }
49             }
50              
51              
52             #
53             # Arguments are :
54             # nbits, [hash,] packed_val, "name1:bitfld1_width", "name2:bitfld2_width",etc
55             # "nameX:bitfield_widths" are in the same order than in the C struct
56             # Returns values for each bitfield in the same order
57             sub __unpack_fields
58             {
59 0     0     my $cur_shift = shift; # Bit width...
60 0           my($ref_hash, $uint);
61 0           my @result;
62              
63 0           $ref_hash = shift;
64 0 0         if (ref($ref_hash) eq 'HASH')
65             {
66 0           $uint = shift;
67             }
68             else
69             {
70 0           $uint = $ref_hash;
71 0           $ref_hash = undef;
72             }
73              
74 0 0         $uint = unpack($cur_shift == 32 ? 'N' : ($cur_shift == 16 ? 'n' : 'C'),
    0          
75             $uint);
76              
77 0           foreach my $width_str (@_)
78             {
79 0           my($name, $width) = split(':', $width_str);
80              
81 0 0         $width = $cur_shift if $width eq '*';
82              
83 0           $cur_shift -= $width;
84              
85 0           my $value = ($uint >> $cur_shift) & ((1 << $width) - 1);
86              
87 0 0         $ref_hash->{$name} = $value if defined $ref_hash;
88 0           push(@result, $value);
89             }
90              
91 0 0         return unless defined wantarray;
92              
93 0 0         return wantarray ? @result : \@result;
94             }
95              
96              
97             #
98             # Arguments are : bits, hash, "name1:bitfld1_width", "name1:bitfld2_width", etc
99             # Returns the packed value
100             sub __pack_fields
101             {
102 0     0     my $uint = 0;
103 0           my $cur_shift = shift;
104 0           my $ref_hash = shift;
105              
106 0 0         my $pack_char = $cur_shift == 32 ? 'N' : ($cur_shift == 16 ? 'n' : 'C');
    0          
107              
108 0           foreach my $width_str (@_)
109             {
110 0           my($name, $width) = split(':', $width_str);
111              
112 0 0         $width = $cur_shift if $width eq '*';
113              
114 0           $cur_shift -= $width;
115              
116 0           my $val = $ref_hash->{$name};
117              
118 0 0         if (defined $val)
119             {
120             # Référence => consider 1
121 0 0         if (ref $val)
    0          
122             {
123 0           $val = 1;
124             }
125             # Boolean value
126             elsif ($width == 1)
127             {
128 0           $val = ($val != 0);
129             }
130             }
131             else
132             {
133 0           $val = 0;
134             }
135              
136 0           $uint |= ($val & ((1 << $width) - 1)) << $cur_shift;
137             }
138              
139 0           return pack($pack_char, $uint);
140             }
141              
142              
143             sub pack_double ($)
144             {
145 0     0 0   my $pack = pack('d', shift);
146              
147 0 0         return $pack if $big_endian;
148              
149 0           return scalar reverse $pack;
150             }
151              
152              
153             sub unpack_double ($)
154             {
155 0     0 0   my $pack = shift;
156              
157 0 0         $pack = scalar reverse $pack unless $big_endian;
158              
159 0           return unpack('d', $pack);
160             }
161              
162              
163             #
164             # Arguments are : hash, "name1:bitfld1_width", "name1:bitfld2_width", etc
165             # in the same order than in the C struct
166             # Returns the packed value
167             sub pack_fields_to_UInt32
168             {
169 0     0 0   return __pack_fields(32, @_);
170             }
171              
172              
173             #
174             # Arguments are : hash, "name1:bitfld1_width", "name1:bitfld2_width", etc
175             # in the same order than in the C struct
176             # Returns the packed value
177             sub pack_fields_to_UInt16
178             {
179 0     0 0   return __pack_fields(16, @_);
180             }
181              
182              
183             #
184             # Arguments are : hash, "name1:bitfld1_width", "name1:bitfld2_width", etc
185             # in the same order than in the C struct
186             # Returns the packed value
187             sub pack_fields_to_UInt8
188             {
189 0     0 0   return __pack_fields(8, @_);
190             }
191              
192              
193             #
194             # Arguments are :
195             # [hash,] packed_val, "name1:bitfld1_width", "name2:bitfld2_width",etc
196             # in the same order than in the C struct
197             # Returns values for each bitfield in the same order
198             sub unpack_UInt8_to_fields
199             {
200 0     0 0   return __unpack_fields(8, @_);
201             }
202              
203              
204             #
205             # Arguments are :
206             # [hash,] packed_val, "name1:bitfld1_width", "name2:bitfld2_width",etc
207             # in the same order than in the C struct
208             # Returns values for each bitfield in the same order
209             sub unpack_UInt16_to_fields
210             {
211 0     0 0   return __unpack_fields(16, @_);
212             }
213              
214              
215             #
216             # Arguments are :
217             # [hash,] packed_val, "name1:bitfld1_width", "name2:bitfld2_width",etc
218             # in the same order than in the C struct
219             # Returns values for each bitfield in the same order
220             sub unpack_UInt32_to_fields
221             {
222 0     0 0   return __unpack_fields(32, @_);
223             }
224              
225              
226             #
227             # Arguments are : hash [, "prefix_"]
228             sub pack_DateType
229             {
230 0     0 0   my($ref_hash, $prefix) = @_;
231              
232 0 0         $prefix = '' unless defined $prefix;
233              
234             # Sometimes we want the date to be totaly zeroed, don't add 1904
235             # in these cases
236 0 0 0       if (defined $ref_hash->{"${prefix}year"}
237             and $ref_hash->{"${prefix}year"} > 0)
238             {
239 0           $ref_hash->{"${prefix}year"} -= 1904;
240             }
241              
242 0           my $pack = pack_fields_to_UInt16($ref_hash,
243             "${prefix}year:7",
244             "${prefix}month:4",
245             "${prefix}day:5");
246              
247             # Sometimes we want the date to be totaly zeroed, don't add 1904
248             # in these cases
249 0 0 0       if (defined $ref_hash->{"${prefix}year"}
250             and $ref_hash->{"${prefix}year"} > 0)
251             {
252 0           $ref_hash->{"${prefix}year"} += 1904;
253             }
254              
255 0           return $pack;
256             }
257              
258              
259             #
260             # Arguments are : [hash,] packed_val [, "prefix_" (only if hash is present)]
261             sub unpack_DateType
262             {
263 0     0 0   my $ref_hash = $_[0];
264 0 0         my $prefix = @_ == 3 ? pop : '';
265 0           my @result;
266              
267 0           @result = unpack_UInt16_to_fields(@_,
268             "${prefix}year:7",
269             "${prefix}month:4",
270             "${prefix}day:5");
271              
272             # Sometimes we want the date to be totaly zeroed, don't add 1904
273             # in these cases
274 0 0 0       if (ref($ref_hash) eq 'HASH' and $ref_hash->{"${prefix}year"} > 0)
275             {
276 0           $ref_hash->{"${prefix}year"} += 1904;
277             }
278              
279 0 0         return unless defined wantarray;
280              
281             # Sometimes we want the date to be totaly zeroed, don't add 1904
282             # in these cases
283 0 0 0       if ($result[0] != 0 or $result[1] != 0 or $result[2] != 0)
      0        
284             {
285 0           $result[0] += 1904;
286             }
287              
288 0 0         return wantarray ? @result : \@result;
289             }
290              
291              
292             #
293             # Arguments are : hash [, "prefix_"]
294             sub pack_TimeType
295             {
296 0     0 0   my($ref_hash, $prefix) = @_;
297              
298 0 0         $prefix = '' unless defined $prefix;
299              
300 0 0         return pack('CC', map { defined($_) ? (ref($_) ? 1 : $_) : 0 }
  0 0          
301             @$ref_hash{"${prefix}hour", "${prefix}min"});
302             }
303              
304              
305             #
306             # Arguments are : [hash,] packed_val [, "prefix_"]
307             sub unpack_TimeType
308             {
309 0     0 0   my($ref_hash, $packed_value, $prefix);
310 0           my @result;
311              
312 0           $ref_hash = shift;
313              
314 0 0         if (ref($ref_hash) eq 'HASH')
315             {
316 0           ($packed_value, $prefix) = @_;
317            
318 0 0         $prefix = '' unless defined $prefix;
319             }
320             else
321             {
322 0           $packed_value = $ref_hash;
323 0           $ref_hash = undef;
324             }
325              
326 0           @result = unpack('CC', $packed_value);
327              
328 0 0         @$ref_hash{"${prefix}hour", "${prefix}min"} = @result if defined $ref_hash;
329              
330 0 0         return unless defined wantarray;
331              
332 0 0         return wantarray ? @result : \@result;
333             }
334              
335             1;
336             __END__