line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Parse::Lotus123::WK4; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Parse::Lotus123::WK4 - extract data from Lotus 1-2-3 .wk4 files |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 OVERVIEW |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
This module extracts data from Lotus 1-2-3 .wk4 files. |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NO DOCUMENTATION |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Procedural API: |
14
|
|
|
|
|
|
|
Parse::Lotus123::WK4::parse takes a filehandle and returns a three-dimensional arrayref. |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
See the source code to wk42csv for a working example. |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 SOURCES |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
Description of WK4 format: |
21
|
|
|
|
|
|
|
L |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
Method for decoding IEEE 80-bit floats: |
24
|
|
|
|
|
|
|
L |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 BUGS |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
This code is experimental, not documented and not properly tested. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 NO WARRANTY |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
This code comes with ABSOLUTELY NO WARRANTY of any kind. |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head1 AUTHOR |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
Copyright 2008 Reckon LLP and Franck Latrémolière. |
37
|
|
|
|
|
|
|
L |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 LICENCE |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under the same terms as Perl. |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=cut |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
|
46
|
1
|
|
|
1
|
|
16891
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
37
|
|
47
|
1
|
|
|
1
|
|
6
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
160
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
BEGIN { |
50
|
|
|
|
|
|
|
|
51
|
1
|
|
|
1
|
|
3
|
$Parse::Lotus123::WK4::VERSION = '0.09'; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# test for float endianness using little-endian 33 33 3b f3, which is a float code for 1.4 |
54
|
|
|
|
|
|
|
|
55
|
1
|
|
|
|
|
20
|
my $testFloat = unpack( 'f', pack( 'h*', 'f33b3333' ) ); |
56
|
1
|
50
|
33
|
|
|
17
|
$Parse::Lotus::WK4::bigEndian = 1 |
57
|
|
|
|
|
|
|
if ( 2.0 * $testFloat > 2.7 && 2.0 * $testFloat < 2.9 ); |
58
|
1
|
|
|
|
|
3
|
$testFloat = unpack( 'f', pack( 'h*', '33333bf3' ) ); |
59
|
1
|
50
|
33
|
|
|
11
|
$Parse::Lotus::WK4::bigEndian = 0 |
60
|
|
|
|
|
|
|
if ( 2.0 * $testFloat > 2.7 && 2.0 * $testFloat < 2.9 ); |
61
|
1
|
50
|
|
|
|
86
|
die "Unable to detect endianness of float storage on your machine" |
62
|
|
|
|
|
|
|
unless defined $Parse::Lotus::WK4::bigEndian; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub decode_lotus_weirdness { |
67
|
1
|
|
|
1
|
0
|
6
|
my $h = unpack 's', pack 'S', $_[0]; |
68
|
1
|
50
|
|
|
|
7
|
return $h / 2 unless $h & 1; |
69
|
1
|
|
|
|
|
3
|
my $sw = $h & 0x0f; |
70
|
|
|
|
|
|
|
{ |
71
|
1
|
|
|
1
|
|
1046
|
use integer; # this makes the right-shift operator signed for the block |
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
3
|
|
72
|
1
|
|
|
|
|
4
|
$h >>= 4; |
73
|
|
|
|
|
|
|
} |
74
|
1
|
50
|
|
|
|
4
|
return $h * 5000 if $sw == 0x1; |
75
|
1
|
50
|
|
|
|
4
|
return $h * 500 if $sw == 0x3; |
76
|
1
|
50
|
|
|
|
11
|
return $h / 20 if $sw == 0x5; |
77
|
0
|
0
|
|
|
|
0
|
return $h / 200 if $sw == 0x7; |
78
|
0
|
0
|
|
|
|
0
|
return $h / 2000 if $sw == 0x9; |
79
|
0
|
0
|
|
|
|
0
|
return $h / 20000 if $sw == 0xb; |
80
|
0
|
0
|
|
|
|
0
|
return $h / 16 if $sw == 0xd; |
81
|
0
|
0
|
|
|
|
0
|
return $h / 64 if $sw == 0xf; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub decode_float80 { |
85
|
1
|
|
|
1
|
0
|
6
|
my( $discard, $mantissa, $hidden, $exponent, $sign ) = |
86
|
|
|
|
|
|
|
unpack 'a11 a52 a1 a15 a1', $_[ 0 ]; |
87
|
1
|
|
|
|
|
5
|
$exponent = unpack( 'v', pack 'b15', $exponent ) - 16383 + 1023; |
88
|
1
|
50
|
33
|
|
|
14
|
($exponent, $mantissa) = (32767, '0' x 52) |
89
|
|
|
|
|
|
|
if $exponent < 0 || $exponent > 2047; |
90
|
1
|
|
|
|
|
4
|
$exponent = unpack 'b11', pack 'v', $exponent; |
91
|
1
|
|
|
|
|
5
|
my $bits64 = pack 'b64', $mantissa . $exponent . $sign; |
92
|
1
|
50
|
|
|
|
4
|
$bits64 = pack 'a' x 8, reverse unpack 'a' x 8, pack 'b64', $bits64 |
93
|
|
|
|
|
|
|
if $Parse::Lotus::WK4::bigEndian; |
94
|
1
|
|
|
|
|
7
|
unpack 'd', $bits64; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub parse($) { |
98
|
1
|
|
|
1
|
0
|
536
|
my $fh = $_[0] ; |
99
|
1
|
|
|
|
|
5
|
my $data = [[[]]]; |
100
|
1
|
|
|
|
|
29
|
while ( read( $fh, my $head, 4 ) == 4 ) { |
101
|
73
|
|
|
|
|
98
|
my ( $code, $len ) = unpack( 'vv', $head ); |
102
|
73
|
|
|
|
|
112
|
my $read = read ($fh, my $byt, $len); |
103
|
73
|
100
|
|
|
|
363
|
if ( $read != $len ) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# warn "Could not read $len bytes"; |
105
|
|
|
|
|
|
|
# no need to warn the user: we are probably just at the end of the file |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
elsif ( $code == 0x16 ) { |
108
|
1
|
|
|
|
|
6
|
my ( $row, $sheet, $col, $align, $text ) = unpack( 'vCCCA*', $byt ); |
109
|
1
|
|
|
|
|
4
|
$text =~ s/"/'/g; |
110
|
1
|
|
|
|
|
6
|
$data->[$sheet][$row][$col] = $text; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
elsif ( $code == 0x17 ) { |
113
|
0
|
|
|
|
|
0
|
my ( $row, $sheet, $col, $b ) = unpack( 'vCCb80', $byt ); |
114
|
0
|
|
|
|
|
0
|
$data->[$sheet][$row][$col] = decode_float80 $b; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
elsif ( $code == 0x19 ) { |
117
|
1
|
|
|
|
|
5
|
my ( $row, $sheet, $col, $b, $formula ) = |
118
|
|
|
|
|
|
|
unpack( 'vCCb80A*', $byt ); |
119
|
1
|
|
|
|
|
13
|
$data->[$sheet][$row][$col] = decode_float80 $b; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
elsif ( $code == 0x18 ) { |
122
|
1
|
|
|
|
|
4
|
my ( $row, $sheet, $col, $b ) = unpack( 'vCCv', $byt ); |
123
|
1
|
|
|
|
|
5
|
$data->[$sheet][$row][$col] = decode_lotus_weirdness $b; |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
} |
126
|
1
|
|
|
|
|
3
|
$data; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
1; |