line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Clarion; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
106318
|
use 5.006; |
|
4
|
|
|
|
|
15
|
|
|
4
|
|
|
|
|
145
|
|
4
|
4
|
|
|
4
|
|
25
|
use strict; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
133
|
|
5
|
4
|
|
|
4
|
|
20
|
use warnings; |
|
4
|
|
|
|
|
12
|
|
|
4
|
|
|
|
|
129
|
|
6
|
|
|
|
|
|
|
|
7
|
4
|
|
|
4
|
|
4479
|
use FileHandle; |
|
4
|
|
|
|
|
59548
|
|
|
4
|
|
|
|
|
23
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '1.02'; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Clarion - Perl module for reading CLARION 2.1 data files |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 DESCRIPTION |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
This is a perl module to access CLARION 2.1 files. |
18
|
|
|
|
|
|
|
At the moment only read access to the files is implemented. |
19
|
|
|
|
|
|
|
"Encrypted" (owned) files are processed transparently, |
20
|
|
|
|
|
|
|
there is no need to specify the password of a file. |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 SYNOPSIS |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
use Clarion; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
my $dbh=new Clarion "customer.dat"; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
print $dbh->file_struct; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
for ( 1 .. $dbh->last_record ) { |
31
|
|
|
|
|
|
|
my $r=$dbh->get_record_hash($_); |
32
|
|
|
|
|
|
|
next if $r->{_DELETED}; |
33
|
|
|
|
|
|
|
print $r->{CODE}." ".$r->{NAME}." ".$r->{PHONE}."\n"; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
$dbh->close(); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 METHODS |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=over 4 |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=cut |
43
|
|
|
|
|
|
|
|
44
|
0
|
|
|
0
|
0
|
0
|
sub FILLOCK { 0x01; } # file is locked |
45
|
16
|
|
|
16
|
0
|
50
|
sub FILOWN { 0x02; } # file is owned |
46
|
48
|
|
|
48
|
0
|
122
|
sub FILCRYP { 0x04; } # records are encrypted |
47
|
13
|
|
|
13
|
0
|
56
|
sub FILMEMO { 0x08; } # memo file exists |
48
|
0
|
|
|
0
|
0
|
0
|
sub FILCOMP { 0x10; } # file is compressed |
49
|
6
|
|
|
6
|
0
|
18
|
sub FILRCLM { 0x20; } # reclaim deleted records |
50
|
6
|
|
|
6
|
0
|
15
|
sub FILREAD { 0x40; } # file is read only |
51
|
6
|
|
|
6
|
0
|
27
|
sub FILCRET { 0x80; } # file may be created |
52
|
|
|
|
|
|
|
|
53
|
0
|
|
|
0
|
0
|
0
|
sub RECNEW { 0x01; } # bit 0 - new record |
54
|
0
|
|
|
0
|
0
|
0
|
sub RECOLD { 0x02; } # bit 1 - old record |
55
|
0
|
|
|
0
|
0
|
0
|
sub RECREV { 0x04; } # bit 2 - revised record |
56
|
49
|
|
|
49
|
0
|
83
|
sub RECDEL { 0x10; } # bit 4 - deleted record |
57
|
0
|
|
|
0
|
0
|
0
|
sub RECHLD { 0x40; } # bit 6 - record held |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=item $h=new Clarion ["file.dat" [, 1]] |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Create object for reading Clarion file. If file name is specified then |
62
|
|
|
|
|
|
|
associate the DAT file with the object. "Encrypted" files are processed |
63
|
|
|
|
|
|
|
transparently, you do not need to specify the password of a file. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
If the third argument (skipMemo) specified, memo field will not be |
66
|
|
|
|
|
|
|
processed at all. |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=cut |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub new { |
71
|
11
|
|
|
11
|
0
|
281
|
my $self={}; |
72
|
11
|
|
|
|
|
24
|
bless $self, shift; |
73
|
|
|
|
|
|
|
|
74
|
11
|
100
|
|
|
|
97
|
$self->open(@_) if @_; |
75
|
11
|
|
|
|
|
32
|
return $self; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=item $h->close |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
Close all open file handles. |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=cut |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub close { |
85
|
17
|
|
|
17
|
1
|
2931
|
my $self=shift; |
86
|
17
|
100
|
|
|
|
55
|
if($self->{fh}) { |
87
|
10
|
|
|
|
|
103
|
$self->{fh}->close(); |
88
|
10
|
|
|
|
|
199
|
delete $self->{fh}; |
89
|
|
|
|
|
|
|
} |
90
|
17
|
100
|
|
|
|
258
|
if($self->{fhMemo}) { |
91
|
4
|
|
|
|
|
15
|
$self->{fhMemo}->close(); |
92
|
4
|
|
|
|
|
288
|
delete $self->{fhMemo}; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub DESTROY { |
97
|
11
|
|
|
11
|
|
3101
|
shift->close; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
=item $h->open('file.dat' [, 1]) |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
Read and parse header of Clarion file. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
If second argument given, skip processing of memo field. |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=cut |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub open { |
109
|
10
|
|
|
10
|
1
|
22
|
my ($self, $fileName, $skipMemo)=@_; |
110
|
|
|
|
|
|
|
|
111
|
10
|
50
|
|
|
|
66
|
my $fh=new FileHandle $fileName |
112
|
|
|
|
|
|
|
or die("Cannot open '$fileName': $!\n"); |
113
|
10
|
|
|
|
|
1075
|
binmode($fh); |
114
|
10
|
|
|
|
|
38
|
$self->{fh}=$fh; |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Read file signature & header |
117
|
10
|
|
|
|
|
37
|
my ($filesig, $sfatr)=unpack('a2 S', $self->readData(4, 'header')); |
118
|
10
|
50
|
|
|
|
33
|
die "Not a Clarion 2.1 file '$fileName'!\n" if $filesig ne 'C3'; |
119
|
10
|
|
|
|
|
22
|
$self->{name}=$fileName; |
120
|
10
|
|
|
|
|
20
|
$self->{sfatr}=$sfatr; |
121
|
10
|
|
|
|
|
25
|
my $header=$self->readData(2*9+31+9*4-4, 'header'); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# File is encrypted? |
124
|
10
|
100
|
|
|
|
138
|
if($sfatr & FILOWN) { |
125
|
|
|
|
|
|
|
# Looking for key; 4 variants exist |
126
|
7
|
|
|
|
|
29
|
$self->{Key}=[unpack('x8 CX2C', $header)]; # numdels, high word |
127
|
|
|
|
|
|
|
# $self->{Key}=[unpack('x68 CX2C', $header)]; # reserved, low word |
128
|
|
|
|
|
|
|
# $self->{Key}=[unpack('x70 CX2C', $header)]; # reserved, high word |
129
|
|
|
|
|
|
|
# $self->{Key}=[unpack('x68 CC', $header)]; # reserved, middle word |
130
|
7
|
|
|
|
|
24
|
$header=$self->decrypt($header); |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# Parse header itself |
134
|
10
|
|
|
|
|
111
|
my @X=unpack('C L L S S S S L L L L A12 A12 A3 A3 S S L L L S', $header); |
135
|
10
|
|
|
|
|
35
|
foreach my $f(qw(numbkeys numrecs numdels numflds numpics nummars reclen offset |
136
|
|
|
|
|
|
|
logeof logbof freerec recname memnam filpre recpre memolen memowid |
137
|
|
|
|
|
|
|
reserved chgtime chgdate reserved2)) { |
138
|
210
|
|
|
|
|
450
|
$self->{header}{$f}=shift @X; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# Read field descriptions & build record template |
142
|
10
|
|
|
|
|
30
|
$self->{fields}=[]; |
143
|
10
|
|
|
|
|
20
|
$self->{decimal_fields}=[]; |
144
|
10
|
|
|
|
|
31
|
$self->{record}{unpack}=''; |
145
|
10
|
|
|
|
|
33
|
$self->{record}{No}=0; |
146
|
10
|
|
|
|
|
46
|
for(my $i=0; $i<$self->{header}{numflds}; $i++) { |
147
|
74
|
|
|
|
|
178
|
@X=unpack('C A16 S S C C S S', $self->readData(3+16+2*4, 'field descriptor', 1)); |
148
|
74
|
|
|
|
|
288
|
my $fd={}; |
149
|
74
|
|
|
|
|
315
|
foreach my $f(qw(fldtype fldname foffset length decsig decdec arrnum picnum)) { |
150
|
592
|
|
|
|
|
1120
|
$fd->{$f}=shift @X; |
151
|
|
|
|
|
|
|
} |
152
|
74
|
|
|
|
|
109
|
push @{$self->{fields}}, $fd; |
|
74
|
|
|
|
|
152
|
|
153
|
74
|
100
|
|
|
|
181
|
push @{$self->{decimal_fields}}, $fd if 8==$fd->{fldtype}; |
|
17
|
|
|
|
|
32
|
|
154
|
74
|
|
|
|
|
107
|
my $n=$fd->{fldname}; |
155
|
74
|
|
|
|
|
341
|
$n=~s/^.+?://; |
156
|
74
|
|
|
|
|
160
|
$fd->{Name}=$n; |
157
|
74
|
|
|
|
|
187
|
$self->{field_map}{$n}=$fd->{No}=$i; |
158
|
74
|
|
|
|
|
135
|
my $c=qw(a l d A A C s G)[$fd->{fldtype}]; |
159
|
74
|
100
|
|
|
|
140
|
$c='a' unless $c; |
160
|
74
|
100
|
|
|
|
375
|
$c.=$fd->{length} if uc($c)eq 'A'; |
161
|
74
|
100
|
|
|
|
180
|
$c='a'.$fd->{length}.' X'.$fd->{length}.' ' if 'G' eq $c; |
162
|
74
|
|
|
|
|
297
|
$self->{record}{unpack}.=$c.' '; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# Read key descriptions |
166
|
10
|
|
|
|
|
41
|
$self->{keys}=[]; |
167
|
10
|
|
|
|
|
44
|
for(my $i=$self->{header}{numbkeys}; $i>0; $i--) { |
168
|
21
|
|
|
|
|
50
|
@X=unpack('C A16 C C', $self->readData(1+16+1+1, 'key descriptor', 1)); |
169
|
21
|
|
|
|
|
45
|
my $kd={}; |
170
|
21
|
|
|
|
|
33
|
foreach my $f(qw(numcomps keynams comptype complen)) { |
171
|
84
|
|
|
|
|
172
|
$kd->{$f}=shift @X; |
172
|
|
|
|
|
|
|
} |
173
|
21
|
|
|
|
|
31
|
push @{$self->{keys}}, $kd; |
|
21
|
|
|
|
|
41
|
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# Read key parts |
176
|
21
|
|
|
|
|
38
|
$kd->{parts}=[]; |
177
|
21
|
|
|
|
|
61
|
for(my $j=$kd->{numcomps}; $j>0; $j--) { |
178
|
28
|
|
|
|
|
60
|
@X=unpack('C S S C', $self->readData(1+2+2+1, 'key element', 1)); |
179
|
28
|
|
|
|
|
58
|
my $kp={}; |
180
|
28
|
|
|
|
|
41
|
foreach my $f(qw(fldtype fldnum elmoff elmlen)) { |
181
|
112
|
|
|
|
|
226
|
$kp->{$f}=shift @X; |
182
|
|
|
|
|
|
|
} |
183
|
28
|
|
|
|
|
39
|
push @{$kd->{parts}}, $kp; |
|
28
|
|
|
|
|
122
|
|
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
10
|
100
|
100
|
|
|
46
|
return if defined($skipMemo) or !($sfatr & FILMEMO); |
188
|
|
|
|
|
|
|
# Reading memo... |
189
|
4
|
|
|
|
|
24
|
$fileName=~s/\.[^\.\\\/]*$//; |
190
|
4
|
|
|
|
|
8
|
$fileName.='.mem'; |
191
|
4
|
50
|
|
|
|
96
|
$fh=new FileHandle $fileName |
192
|
|
|
|
|
|
|
or die("Cannot open memo '$fileName': $!\n"); |
193
|
4
|
|
|
|
|
392
|
binmode($fh); |
194
|
4
|
|
|
|
|
9
|
$self->{fhMemo}=$fh; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# Read memo file signature |
197
|
4
|
|
|
|
|
76
|
read($fh, $filesig, 2); |
198
|
4
|
50
|
|
|
|
18
|
die "Not a Clarion 2.1 memo '$fileName'!\n" if $filesig ne 'M3'; |
199
|
4
|
|
|
|
|
43
|
my $m={ |
200
|
|
|
|
|
|
|
isMemo=>1, |
201
|
4
|
|
|
|
|
12
|
No=>scalar @{$self->{fields}}, |
202
|
|
|
|
|
|
|
Name=>$self->{header}{memnam}, |
203
|
|
|
|
|
|
|
fldname=>$self->{header}{memnam}.':'.$self->{header}{filpre}, |
204
|
|
|
|
|
|
|
length=>$self->{header}{memolen}, |
205
|
|
|
|
|
|
|
}; |
206
|
4
|
|
|
|
|
7
|
push @{$self->{fields}}, $m; |
|
4
|
|
|
|
|
11
|
|
207
|
4
|
|
|
|
|
17
|
$self->{field_map}{$m->{Name}}=$m->{No}; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=item $n=$dbh->last_record; |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
Returns the number of records in the database file. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=cut |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub last_record { |
217
|
3
|
|
|
3
|
1
|
1329
|
return shift->{header}{numrecs}; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=item $n=$dbh->bof; |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
Returns the physical number of first logical record. |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=cut |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
sub bof { |
227
|
0
|
|
|
0
|
1
|
0
|
return shift->{header}{logbof}; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=item $n=$dbh->eof; |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
Returns the physical number of last logical record. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=cut |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub eof { |
237
|
0
|
|
|
0
|
1
|
0
|
return shift->{header}{logeof}; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# Internal function to read a record |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub readRecord { |
243
|
38
|
|
|
38
|
0
|
42
|
my ($self, $n)=@_; |
244
|
38
|
|
66
|
|
|
108
|
$n||=$self->{record}{No}+1; |
245
|
38
|
100
|
66
|
|
|
177
|
return if $n<1 or $n>$self->{header}{numrecs}; |
246
|
35
|
|
|
|
|
94
|
$self->{record}{data}=[]; |
247
|
35
|
|
|
|
|
71
|
$self->{record}{No}=$n; |
248
|
35
|
|
|
|
|
295
|
seek($self->{fh}, $self->{header}{offset}+$self->{header}{reclen}*($n-1), 0); |
249
|
|
|
|
|
|
|
|
250
|
35
|
|
|
|
|
76
|
($self->{record}{rhd}, $self->{record}{rptr})=unpack('C L', $self->readData(5, 'record')); |
251
|
35
|
|
|
|
|
114
|
my @Data=unpack($self->{record}{unpack}, |
252
|
|
|
|
|
|
|
$self->readData($self->{header}{reclen}-5, 'record', $self->{sfatr} & FILCRYP)); |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# Convert decimal() fields, if any |
255
|
35
|
|
|
|
|
58
|
foreach my $f(@{$self->{decimal_fields}}) { |
|
35
|
|
|
|
|
62
|
|
256
|
49
|
|
|
|
|
121
|
$Data[$f->{No}]=unpackBCD($Data[$f->{No}], $f->{decsig}, $f->{decdec}); |
257
|
|
|
|
|
|
|
} |
258
|
35
|
|
|
|
|
74
|
$self->{record}{data}=\@Data; |
259
|
|
|
|
|
|
|
|
260
|
35
|
100
|
|
|
|
101
|
return 1 unless $self->{fhMemo}; |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# Read memo... |
263
|
14
|
|
|
|
|
16
|
my $memo; |
264
|
14
|
50
|
|
|
|
29
|
$n=($self->{record}{rhd} & RECDEL)? 0 : $self->{record}{rptr}; |
265
|
14
|
|
|
|
|
41
|
while($n) { |
266
|
7
|
|
|
|
|
54
|
seek($self->{fhMemo}, ($n-1)*256+6, 0); |
267
|
7
|
|
|
|
|
25
|
$n=unpack('L', $self->readMemo(4)); |
268
|
7
|
|
|
|
|
18
|
my $m=$self->readMemo(252); |
269
|
7
|
100
|
|
|
|
19
|
$m=$self->decrypt($m) if $self->{sfatr} & FILCRYP; |
270
|
7
|
50
|
|
|
|
20
|
$memo='' unless defined($memo); |
271
|
7
|
|
|
|
|
21
|
$memo.=$m; |
272
|
|
|
|
|
|
|
} |
273
|
14
|
100
|
|
|
|
104
|
$memo=~s/( +|\00+)\z// if $memo; |
274
|
14
|
|
|
|
|
26
|
push @Data, $memo; |
275
|
|
|
|
|
|
|
|
276
|
14
|
|
|
|
|
57
|
return 1; |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
=item @r=$dbh->get_record([ $n [, @fields]]); |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
Returns a list of data (field values) from the specified record. |
282
|
|
|
|
|
|
|
The first parameter in the call is the number of the physical |
283
|
|
|
|
|
|
|
record. If you do not specify any other parameters, all fields are |
284
|
|
|
|
|
|
|
returned in the same order as they appear in the file. You can also |
285
|
|
|
|
|
|
|
put list of field names after the record number and then only those |
286
|
|
|
|
|
|
|
will be returned. The first value of the returned list is always the |
287
|
|
|
|
|
|
|
logical (0 or not 0) value saying whether the record is deleted or not. |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
If first argument is omited (or undef) then reads next record from file. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=cut |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
sub get_record { |
294
|
36
|
|
|
36
|
1
|
2634
|
my ($self, $n, @fields)=@_; |
295
|
|
|
|
|
|
|
|
296
|
36
|
100
|
|
|
|
64
|
$self->readRecord($n) or return; |
297
|
|
|
|
|
|
|
|
298
|
33
|
50
|
|
|
|
105
|
return ($self->{record}{rhd} & RECDEL, @{$self->{record}{data}}) |
|
33
|
|
|
|
|
155
|
|
299
|
|
|
|
|
|
|
unless @fields; |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
return |
302
|
0
|
|
|
|
|
0
|
$self->{record}{rhd} & RECDEL, |
303
|
|
|
|
|
|
|
map($self->{record}{data}[$self->{field_map}{$_}], @fields); |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=item $r=$dbh->get_record_hash([ $n [, @fields]]); |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
Returns reference to hash containing field values indexed by field names. |
309
|
|
|
|
|
|
|
The name of the deleted flag is C<_DELETED>. The first parameter in the call |
310
|
|
|
|
|
|
|
is the number of the physical record (can be omited to read next record if |
311
|
|
|
|
|
|
|
avaialable). If you do not specify any other parameters, all fields are returned. |
312
|
|
|
|
|
|
|
You can also put list of field names after the record number and then only those |
313
|
|
|
|
|
|
|
will be returned. |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=cut |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
sub get_record_hash { |
318
|
2
|
|
|
2
|
1
|
8
|
my ($self, $n, @fields)=@_; |
319
|
|
|
|
|
|
|
|
320
|
2
|
50
|
|
|
|
8
|
$self->readRecord($n) or return; |
321
|
|
|
|
|
|
|
|
322
|
2
|
|
|
|
|
48
|
my %res= @fields ? |
323
|
|
|
|
|
|
|
map(($_, $self->{record}{data}[$self->{field_map}{$_}]), @fields) : |
324
|
2
|
50
|
|
|
|
5
|
map(($_->{Name}, $self->{record}{data}[$_->{No}]), @{$self->{fields}}); |
325
|
|
|
|
|
|
|
|
326
|
2
|
|
|
|
|
10
|
$res{_DELETED}=$self->{record}{rhd} & RECDEL; |
327
|
2
|
|
|
|
|
26
|
return \%res; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=item $struct = $dbh->file_struct; |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
This returns CLARION file structure as a string. |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=cut |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub file_struct { |
337
|
6
|
|
|
6
|
1
|
1029
|
my $self=shift; |
338
|
|
|
|
|
|
|
|
339
|
6
|
|
|
|
|
12
|
my $res=$self->{name}; |
340
|
6
|
|
|
|
|
25
|
$res=~s/\.dat$//i; |
341
|
6
|
|
|
|
|
20
|
$res=~s/^.*[\/\\]//; |
342
|
6
|
|
|
|
|
11
|
$res=uc($res); |
343
|
|
|
|
|
|
|
|
344
|
6
|
|
|
|
|
23
|
$res.="\tFILE,NAME('$res'),PRE('$self->{header}{filpre}')"; |
345
|
|
|
|
|
|
|
|
346
|
6
|
100
|
|
|
|
16
|
$res.=",OWNER('???')" if $self->{sfatr} & FILOWN; |
347
|
6
|
100
|
|
|
|
18
|
$res.=",ENCRYPT" if $self->{sfatr} & FILCRYP; |
348
|
6
|
100
|
|
|
|
15
|
$res.=",CREATE" if $self->{sfatr} & FILCRET; |
349
|
6
|
50
|
|
|
|
55
|
$res.=",RECLAIM" if $self->{sfatr} & FILRCLM; |
350
|
6
|
100
|
|
|
|
24
|
$res.=",PROTECT" if $self->{sfatr} & FILREAD; |
351
|
6
|
100
|
|
|
|
14
|
$res.="\n$self->{header}{memnam}\tMEMO($self->{header}{memolen})" |
352
|
|
|
|
|
|
|
if $self->{sfatr} & FILMEMO; |
353
|
|
|
|
|
|
|
|
354
|
6
|
|
|
|
|
15
|
$res.="\n$self->{header}{recname}\tRECORD\n"; |
355
|
|
|
|
|
|
|
|
356
|
6
|
|
|
|
|
8
|
for my $f(@{$self->{fields}}) { |
|
6
|
|
|
|
|
14
|
|
357
|
45
|
100
|
|
|
|
85
|
next if $f->{isMemo}; |
358
|
42
|
|
|
|
|
59
|
$res.=$f->{Name}."\t"; |
359
|
42
|
|
|
|
|
52
|
my $t=qw(? LONG REAL . . BYTE SHORT . DECIMAL)[$f->{fldtype}]; |
360
|
42
|
50
|
33
|
|
|
177
|
if(!$t or '?' eq $t) { |
361
|
0
|
|
|
|
|
0
|
$t='UNKNOWN TYPE'; |
362
|
0
|
|
|
|
|
0
|
$res.='!'; |
363
|
|
|
|
|
|
|
} |
364
|
42
|
100
|
|
|
|
63
|
if('.' eq $t){ |
365
|
9
|
|
|
|
|
14
|
$res.="STRING($f->{length})"; |
366
|
9
|
100
|
|
|
|
22
|
$res.="\t!GROUP" if 7==$f->{fldtype}; |
367
|
|
|
|
|
|
|
} else { |
368
|
33
|
|
|
|
|
34
|
$res.=$t; |
369
|
33
|
100
|
|
|
|
81
|
$res.="(".($f->{decsig}+$f->{decdec}).",$f->{decdec})" |
370
|
|
|
|
|
|
|
if 8==$f->{fldtype}; |
371
|
|
|
|
|
|
|
} |
372
|
42
|
|
|
|
|
55
|
$res.="\n"; |
373
|
|
|
|
|
|
|
} |
374
|
6
|
|
|
|
|
41
|
return $res."\t. .\n"; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
# Clarion "decryption" |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
sub decrypt { |
380
|
146
|
|
|
146
|
0
|
230
|
my ($self, $str)=@_; |
381
|
146
|
100
|
|
|
|
469
|
return $str unless defined($self->{Key}); |
382
|
110
|
|
|
|
|
132
|
my $res=''; |
383
|
110
|
|
|
|
|
112
|
do{ |
384
|
1858
|
|
|
|
|
2718
|
my($c1, $c2)=unpack('C2', $str); |
385
|
1858
|
100
|
|
|
|
3756
|
defined($c2) or return $res.$str; |
386
|
1748
|
|
|
|
|
3485
|
$res.=pack('C2', $c1^$self->{Key}[0], $c2^$self->{Key}[1]); |
387
|
1748
|
|
|
|
|
4187
|
$str=unpack('x2 a*', $str); |
388
|
|
|
|
|
|
|
}while(1); |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub readData { |
392
|
213
|
|
|
213
|
0
|
330
|
my ($self, $len, $what, $decrypt)=@_; |
393
|
213
|
|
50
|
|
|
1037
|
my $rc=read($self->{fh}, my $buf, $len)||0; |
394
|
213
|
50
|
|
|
|
481
|
die "Read error Clarion file ($what) ($rc bytes read instead of $len)!\n" |
395
|
|
|
|
|
|
|
if $rc!=$len; |
396
|
213
|
100
|
|
|
|
717
|
return $decrypt? $self->decrypt($buf) : $buf; |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub readMemo { |
400
|
14
|
|
|
14
|
0
|
18
|
my ($self, $len)=@_; |
401
|
14
|
|
50
|
|
|
144
|
my $rc=read($self->{fhMemo}, my $buf, $len)||0; |
402
|
14
|
50
|
|
|
|
30
|
die "Read error Clarion memo ($rc bytes read instead of $len)!\n" |
403
|
|
|
|
|
|
|
if $rc!=$len; |
404
|
14
|
|
|
|
|
31
|
return $buf; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# Convert BCD to string |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub unpackBCD { |
410
|
49
|
|
|
49
|
0
|
70
|
my ($bcd, $decsig, $decdec)=@_; |
411
|
49
|
|
|
|
|
94
|
$bcd=unpack('H*', $bcd); |
412
|
|
|
|
|
|
|
|
413
|
49
|
100
|
|
|
|
107
|
my $sign=substr($bcd, 0, 1) eq '0' ? '' : '-'; |
414
|
49
|
|
|
|
|
63
|
$bcd=substr($bcd, 1); |
415
|
49
|
50
|
|
|
|
112
|
$bcd=~s/\D/9/g and |
416
|
|
|
|
|
|
|
warn "Incorrect DECIMAL value!\n"; |
417
|
|
|
|
|
|
|
|
418
|
49
|
|
|
|
|
66
|
my $sig=substr($bcd, 0, $decsig); |
419
|
49
|
|
|
|
|
122
|
$sig=~s/^0+//; |
420
|
49
|
100
|
|
|
|
84
|
$sig='0' if !length($sig); |
421
|
|
|
|
|
|
|
|
422
|
49
|
|
|
|
|
62
|
my $dec=substr($bcd, $decsig, $decdec); |
423
|
49
|
|
|
|
|
85
|
$dec=~s/0+$//; |
424
|
49
|
100
|
|
|
|
101
|
$sig.='.' if length($dec); |
425
|
|
|
|
|
|
|
|
426
|
49
|
|
|
|
|
178
|
return $sign.$sig.$dec; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
1; |
430
|
|
|
|
|
|
|
__END__ |