line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package D64::Disk::Dir; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
D64::Disk::Dir - Handling entire Commodore (D64/D71/D81) disk image directories (using Per Olofsson's "diskimage.c" library) |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use D64::Disk::Dir; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# Read entire D64/D71/D81 disk image directory from file on disk in one step: |
12
|
|
|
|
|
|
|
my $d64DiskDirObj = D64::Disk::Dir->new($filename); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# Read entire D64/D71/D81 disk image directory from file on disk in two steps: |
15
|
|
|
|
|
|
|
my $d64DiskDirObj = D64::Disk::Dir->new(); |
16
|
|
|
|
|
|
|
my $readOK = $d64DiskDirObj->read_dir($filename); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Read new D64/D71/D81 disk directory replacing currently loaded dir with it: |
19
|
|
|
|
|
|
|
my $readOK = $d64DiskDirObj->read_dir($filename); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# Get disk directory title converted to ASCII string: |
22
|
|
|
|
|
|
|
my $convert2ascii = 1; |
23
|
|
|
|
|
|
|
my $title = $d64DiskDirObj->get_title($convert2ascii); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
# Get disk directory ID converted to ASCII string: |
26
|
|
|
|
|
|
|
my $convert2ascii = 1; |
27
|
|
|
|
|
|
|
my $diskID = $d64DiskDirObj->get_id($convert2ascii); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# Get number of blocks free: |
30
|
|
|
|
|
|
|
my $blocksFree = $d64DiskDirObj->get_blocks_free(); |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# Get number of directory entries: |
33
|
|
|
|
|
|
|
my $num_entries = $d64DiskDirObj->num_entries(); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Get directory entry at the specified position: |
36
|
|
|
|
|
|
|
my $entryObj = $d64DiskDirObj->get_entry($index); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# Get binary file data from a directory entry at the specified position: |
39
|
|
|
|
|
|
|
my $data = $d64DiskDirObj->get_file_data($index); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# Print out the entire directory content to the standard output: |
42
|
|
|
|
|
|
|
$d64DiskDirObj->print_dir(); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head1 DESCRIPTION |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
This package provides an abstract layer above D64::Disk::Image module, enabling user to handle D64 disk image directories in a higher-level object-oriented way. |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head1 METHODS |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=cut |
51
|
|
|
|
|
|
|
|
52
|
4
|
|
|
4
|
|
278610
|
use bytes; |
|
4
|
|
|
|
|
62
|
|
|
4
|
|
|
|
|
16
|
|
53
|
4
|
|
|
4
|
|
100
|
use strict; |
|
4
|
|
|
|
|
5
|
|
|
4
|
|
|
|
|
59
|
|
54
|
4
|
|
|
4
|
|
16
|
use warnings; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
102
|
|
55
|
|
|
|
|
|
|
|
56
|
4
|
|
|
4
|
|
18
|
use base qw( Exporter ); |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
658
|
|
57
|
|
|
|
|
|
|
our %EXPORT_TAGS = (); |
58
|
|
|
|
|
|
|
$EXPORT_TAGS{'all'} = []; |
59
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
60
|
|
|
|
|
|
|
our @EXPORT = qw(); |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
our $VERSION = '0.04'; |
63
|
|
|
|
|
|
|
|
64
|
4
|
|
|
4
|
|
23
|
use Carp qw/carp croak verbose/; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
500
|
|
65
|
|
|
|
|
|
|
|
66
|
4
|
|
|
4
|
|
1500
|
use D64::Disk::Dir::Entry; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
111
|
|
67
|
4
|
|
|
4
|
|
20
|
use D64::Disk::Image qw(:all); |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
5312
|
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# Mapping file types onto file type constants: |
70
|
|
|
|
|
|
|
our %file_type_constants = ( |
71
|
|
|
|
|
|
|
'del' => T_DEL, |
72
|
|
|
|
|
|
|
'seq' => T_SEQ, |
73
|
|
|
|
|
|
|
'prg' => T_PRG, |
74
|
|
|
|
|
|
|
'usr' => T_USR, |
75
|
|
|
|
|
|
|
'rel' => T_REL, |
76
|
|
|
|
|
|
|
'cbm' => T_CBM, |
77
|
|
|
|
|
|
|
'dir' => T_DIR, |
78
|
|
|
|
|
|
|
'???' => 0xFF, |
79
|
|
|
|
|
|
|
); |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head2 new |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Create empty C object without loading disk image directory yet: |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
my $d64DiskDirObj = D64::Disk::Dir->new(); |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
Create new C object and read entire D64/D71/D81 disk image directory from file on disk for further access. |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
my $d64DiskDirObj = D64::Disk::Dir->new($filename); |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
A valid C object is returned upon success, an undefined value otherwise. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=cut |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub new { |
96
|
26
|
|
|
26
|
1
|
25992
|
my $this = shift; |
97
|
26
|
|
33
|
|
|
106
|
my $class = ref($this) || $this; |
98
|
26
|
|
|
|
|
39
|
my $self = {}; |
99
|
26
|
|
|
|
|
43
|
bless $self, $class; |
100
|
26
|
|
|
|
|
55
|
my $initOK = $self->_initialize(@_); |
101
|
26
|
50
|
|
|
|
40
|
if ($initOK) { |
102
|
26
|
|
|
|
|
61
|
return $self; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
else { |
105
|
0
|
|
|
|
|
0
|
return undef; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub _initialize { |
110
|
26
|
|
|
26
|
|
31
|
my $self = shift; |
111
|
26
|
|
|
|
|
33
|
my $filename = shift; |
112
|
|
|
|
|
|
|
# Read entire disk image directory: |
113
|
26
|
100
|
|
|
|
49
|
if (defined $filename) { |
114
|
24
|
|
|
|
|
46
|
my $readOK = $self->read_dir($filename); |
115
|
24
|
50
|
|
|
|
58
|
return 0 unless $readOK; |
116
|
|
|
|
|
|
|
} |
117
|
26
|
|
|
|
|
35
|
return 1; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub _check_dir_read { |
121
|
55
|
|
|
55
|
|
57
|
my $self = shift; |
122
|
|
|
|
|
|
|
# Raise error if directory has not been read yet: |
123
|
55
|
50
|
|
|
|
95
|
croak "Unable to perform requested operation, because disk image directory has not been read yet" if $self->{'DIR_READ'} == 0; |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub _init_dir { |
127
|
25
|
|
|
25
|
|
32
|
my $self = shift; |
128
|
|
|
|
|
|
|
# Directory has not been read yet: |
129
|
25
|
|
|
|
|
47
|
$self->{'DIR_READ'} = 0; |
130
|
25
|
|
|
|
|
46
|
$self->_release_d64_image(); |
131
|
25
|
|
|
|
|
52
|
$self->_clear_dir_entries(); |
132
|
25
|
|
|
|
|
29
|
delete $self->{'D64_FILE_NAME'}; |
133
|
25
|
|
|
|
|
30
|
delete $self->{'DIR_INFO'}; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=head2 read_dir |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
Read entire D64/D71/D81 disk image directory from file on disk, replacing currently loaded directory (if any). |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
$d64DiskDirObj->read_dir($filename); |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
Returns true value upon success, and false otherwise. |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=cut |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub read_dir { |
147
|
25
|
|
|
25
|
1
|
45
|
my $self = shift; |
148
|
25
|
|
|
|
|
30
|
my $filename = shift; |
149
|
|
|
|
|
|
|
# We do not verify file existence here, D64::Disk::Image module croaks on inexisting files: |
150
|
25
|
|
|
|
|
51
|
$self->_init_dir(); |
151
|
|
|
|
|
|
|
# Load image into RAM: |
152
|
25
|
|
|
|
|
65
|
my $d64DiskImageObj = D64::Disk::Image->load_image($filename); |
153
|
25
|
|
|
|
|
2911
|
$self->{'D64_DISK_IMAGE'} = $d64DiskImageObj; |
154
|
25
|
|
|
|
|
42
|
$self->{'D64_FILE_NAME'} = $filename; |
155
|
|
|
|
|
|
|
# Open directory for reading: |
156
|
25
|
|
|
|
|
66
|
my $dir = $d64DiskImageObj->open('$', T_PRG, F_READ); |
157
|
|
|
|
|
|
|
# Get disk-wide directory information: |
158
|
25
|
|
|
|
|
901
|
$self->_get_dir_info($dir); |
159
|
|
|
|
|
|
|
# Read directory blocks: |
160
|
25
|
|
|
|
|
44
|
my $readOK = $self->_read_dir_blocks($dir); |
161
|
25
|
50
|
|
|
|
41
|
return 0 unless $readOK; |
162
|
|
|
|
|
|
|
# Close directory: |
163
|
25
|
|
|
|
|
53
|
$dir->close(); |
164
|
|
|
|
|
|
|
# Store D64 disk image filename for further checks: |
165
|
25
|
|
|
|
|
154
|
$self->{'FILENAME'} = $filename; |
166
|
|
|
|
|
|
|
# Directory has been read successfully: |
167
|
25
|
|
|
|
|
32
|
$self->{'DIR_READ'} = 1; |
168
|
25
|
|
|
|
|
71
|
return 1; |
169
|
|
|
|
|
|
|
# There was a problem reading directory: |
170
|
0
|
|
|
|
|
0
|
return 0; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub _read_dir_blocks { |
174
|
25
|
|
|
25
|
|
32
|
my $self = shift; |
175
|
25
|
|
|
|
|
27
|
my $dir = shift; |
176
|
|
|
|
|
|
|
# Read first block into buffer: |
177
|
25
|
|
|
|
|
51
|
my ($counter, $buffer) = $dir->read(254); |
178
|
25
|
50
|
|
|
|
276
|
if ($counter != 254) { |
179
|
0
|
|
|
|
|
0
|
carp 'BAM read failed'; |
180
|
0
|
|
|
|
|
0
|
return 0; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
# Read directory blocks: |
183
|
25
|
|
|
|
|
32
|
while (1) { |
184
|
50
|
|
|
|
|
85
|
my ($counter, $buffer) = $dir->read(254); |
185
|
50
|
100
|
|
|
|
484
|
last unless $counter == 254; |
186
|
25
|
|
|
|
|
66
|
for (my $offset = -2; $offset < 254; $offset += 32) { |
187
|
|
|
|
|
|
|
# If file type != 0: |
188
|
200
|
|
|
|
|
265
|
my $file_type = ord (substr $buffer, $offset + 2, 1); |
189
|
200
|
100
|
|
|
|
329
|
if ($file_type != 0) { |
190
|
|
|
|
|
|
|
# Create new D64::Disk::Dir::Entry object: |
191
|
75
|
|
|
|
|
103
|
my $bytes = substr $buffer, $offset + 2, 30; |
192
|
75
|
|
|
|
|
165
|
my $entryObj = D64::Disk::Dir::Entry->new($bytes); |
193
|
75
|
50
|
|
|
|
115
|
unless (defined $entryObj) { |
194
|
0
|
|
|
|
|
0
|
carp 'Directory blocks read failed'; |
195
|
0
|
|
|
|
|
0
|
return 0; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
# Add it to the list of directory entries: |
198
|
75
|
|
|
|
|
408
|
$self->_add_dir_entry($entryObj); |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
} |
202
|
25
|
|
|
|
|
33
|
return 1; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub _get_dir_info { |
206
|
25
|
|
|
25
|
|
31
|
my $self = shift; |
207
|
25
|
|
|
|
|
27
|
my $dir = shift; |
208
|
25
|
|
|
|
|
29
|
my $d64DiskImageObj = $self->{'D64_DISK_IMAGE'}; |
209
|
|
|
|
|
|
|
# Get number of blocks free: |
210
|
25
|
|
|
|
|
48
|
my $blocksFree = $d64DiskImageObj->blocksfree(); |
211
|
|
|
|
|
|
|
# Get title and ID: |
212
|
25
|
|
|
|
|
161
|
my ($title, $id) = $d64DiskImageObj->title(); |
213
|
25
|
|
|
|
|
287
|
$title = D64::Disk::Image->name_from_rawname($title); |
214
|
25
|
|
|
|
|
198
|
$id = D64::Disk::Image->name_from_rawname($id); |
215
|
|
|
|
|
|
|
# Store directory details in a hash: |
216
|
25
|
|
|
|
|
253
|
$self->{'DIR_INFO'} = { |
217
|
|
|
|
|
|
|
'TITLE' => $title, |
218
|
|
|
|
|
|
|
'ID' => $id, |
219
|
|
|
|
|
|
|
'BLOCKS_FREE' => $blocksFree, |
220
|
|
|
|
|
|
|
}; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub _add_dir_entry { |
224
|
75
|
|
|
75
|
|
82
|
my $self = shift; |
225
|
75
|
|
|
|
|
75
|
my $entryObj = shift; |
226
|
75
|
|
|
|
|
82
|
push @{$self->{'DIR_ENTRIES'}}, $entryObj; |
|
75
|
|
|
|
|
186
|
|
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub _get_dir_entries { |
230
|
46
|
|
|
46
|
|
48
|
my $self = shift; |
231
|
46
|
|
|
|
|
51
|
my $entries = $self->{'DIR_ENTRIES'}; |
232
|
46
|
100
|
|
|
|
65
|
$entries = [] unless defined $entries; |
233
|
46
|
|
|
|
|
59
|
return $entries; |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub _clear_dir_entries { |
237
|
25
|
|
|
25
|
|
32
|
my $self = shift; |
238
|
25
|
|
|
|
|
45
|
$self->{'DIR_ENTRIES'} = []; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head2 get_title |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
Get 16 character disk directory title (PETSCII string): |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
my $convert2ascii = 0; |
246
|
|
|
|
|
|
|
my $title = $d64DiskDirObj->get_title($convert2ascii); |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
Get disk directory title converted to ASCII string: |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
my $convert2ascii = 1; |
251
|
|
|
|
|
|
|
my $title = $d64DiskDirObj->get_title($convert2ascii); |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=cut |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub get_title { |
256
|
3
|
|
|
3
|
1
|
8
|
my $self = shift; |
257
|
3
|
|
|
|
|
4
|
my $convert2ascii = shift; |
258
|
3
|
|
|
|
|
4
|
$self->_check_dir_read(); |
259
|
3
|
|
|
|
|
4
|
my $title = $self->{'DIR_INFO'}->{'TITLE'}; |
260
|
|
|
|
|
|
|
# Convert title to ASCII when necessary: |
261
|
3
|
50
|
|
|
|
19
|
$title = D64::Disk::Image->petscii_to_ascii($title) if $convert2ascii; |
262
|
3
|
|
|
|
|
355
|
return $title; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=head2 get_id |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
Get 2 character disk directory ID (PETSCII string): |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
my $convert2ascii = 0; |
270
|
|
|
|
|
|
|
my $diskID = $d64DiskDirObj->get_id($convert2ascii); |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
Get disk directory ID converted to ASCII string: |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
my $convert2ascii = 1; |
275
|
|
|
|
|
|
|
my $diskID = $d64DiskDirObj->get_id($convert2ascii); |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=cut |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
sub get_id { |
280
|
3
|
|
|
3
|
1
|
9
|
my $self = shift; |
281
|
3
|
|
|
|
|
3
|
my $convert2ascii = shift; |
282
|
3
|
|
|
|
|
16
|
$self->_check_dir_read(); |
283
|
3
|
|
|
|
|
5
|
my $id = $self->{'DIR_INFO'}->{'ID'}; |
284
|
|
|
|
|
|
|
# Convert disk ID to ASCII when necessary: |
285
|
3
|
50
|
|
|
|
16
|
$id = D64::Disk::Image->petscii_to_ascii($id) if $convert2ascii; |
286
|
3
|
|
|
|
|
67
|
return $id; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=head2 get_blocks_free |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
Get number of blocks free: |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
my $blocksFree = $d64DiskDirObj->get_blocks_free(); |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=cut |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
sub get_blocks_free { |
298
|
3
|
|
|
3
|
1
|
10
|
my $self = shift; |
299
|
3
|
|
|
|
|
6
|
$self->_check_dir_read(); |
300
|
3
|
|
|
|
|
4
|
my $blocksFree = $self->{'DIR_INFO'}->{'BLOCKS_FREE'}; |
301
|
3
|
|
|
|
|
4
|
return $blocksFree; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=head2 num_entries |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Get number of directory entries: |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
my $num_entries = $d64DiskDirObj->num_entries(); |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=cut |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub num_entries { |
313
|
23
|
|
|
23
|
1
|
32
|
my $self = shift; |
314
|
23
|
|
|
|
|
36
|
$self->_check_dir_read(); |
315
|
23
|
|
|
|
|
37
|
my $entries_aref = $self->_get_dir_entries(); |
316
|
23
|
|
|
|
|
26
|
my $num_entries = @{$entries_aref}; |
|
23
|
|
|
|
|
31
|
|
317
|
23
|
|
|
|
|
30
|
return $num_entries; |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head2 get_entry |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
Get directory entry at the specified position (index value must be a valid position equal or greater than 0 and less than number of directory entries): |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
my $entryObj = $d64DiskDirObj->get_entry($index); |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
Returns a valid L object upon success, and false otherwise. |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=cut |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
sub get_entry { |
331
|
20
|
|
|
20
|
1
|
47
|
my $self = shift; |
332
|
20
|
|
|
|
|
21
|
my $index = shift; |
333
|
20
|
|
|
|
|
40
|
$self->_check_dir_read(); |
334
|
20
|
|
|
|
|
40
|
my $num_entries = $self->num_entries(); |
335
|
20
|
50
|
33
|
|
|
72
|
if ($index < 0 or $index >= $num_entries) { |
336
|
0
|
|
|
|
|
0
|
carp "Cannot get entry at invalid index position (disk directory contains only ${num_entries} file(s), unable to get entry at position ${index})"; |
337
|
0
|
|
|
|
|
0
|
return undef; |
338
|
|
|
|
|
|
|
} |
339
|
20
|
|
|
|
|
30
|
my $entries_aref = $self->_get_dir_entries(); |
340
|
20
|
|
|
|
|
24
|
my $entryObj = $entries_aref->[$index]; |
341
|
20
|
|
|
|
|
25
|
return $entryObj; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=head2 get_file_data |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
Get binary file data from a directory entry at the specified position: |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
my $data = $d64DiskDirObj->get_file_data($index); |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
Reads data from a file at the specified directory index position (index value must be a valid position equal or greater than 0 and less than number of directory entries). Returns binary file data (including its loading address) upon success, and an undefined value otherwise. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=cut |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
sub get_file_data { |
355
|
1
|
|
|
1
|
1
|
7
|
my $self = shift; |
356
|
1
|
|
|
|
|
2
|
my $index = shift; |
357
|
1
|
|
|
|
|
3
|
$self->_check_dir_read(); |
358
|
1
|
|
|
|
|
2
|
my $entryObj = $self->get_entry($index); |
359
|
1
|
50
|
|
|
|
3
|
unless (defined $entryObj) { |
360
|
0
|
|
|
|
|
0
|
carp "Unable to get file data from an inexisting directory entry (validate first that ${index} file(s) really exist(s) on this disk!)"; |
361
|
0
|
|
|
|
|
0
|
return undef; |
362
|
|
|
|
|
|
|
} |
363
|
1
|
|
|
|
|
2
|
my $d64DiskImageObj = $self->{'D64_DISK_IMAGE'}; |
364
|
|
|
|
|
|
|
# Get filename from the specified directory index position: |
365
|
1
|
|
|
|
|
4
|
my $name = $entryObj->get_name(0); |
366
|
1
|
|
|
|
|
3
|
my $rawname = D64::Disk::Image->rawname_from_name($name); |
367
|
|
|
|
|
|
|
# Get the actual filetype: |
368
|
1
|
|
|
|
|
10
|
my $type = $entryObj->get_type(); |
369
|
1
|
|
|
|
|
3
|
my $filetype = $file_type_constants{$type}; |
370
|
|
|
|
|
|
|
# Open a file for reading: |
371
|
1
|
|
|
|
|
3
|
my $prg = $d64DiskImageObj->open($rawname, $filetype, F_READ); |
372
|
|
|
|
|
|
|
# Read data from file: |
373
|
1
|
|
|
|
|
34
|
my ($counter, $buffer) = $prg->read(); |
374
|
|
|
|
|
|
|
# Close a file: |
375
|
1
|
|
|
|
|
746
|
$prg->close(); |
376
|
1
|
|
|
|
|
10
|
return $buffer; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
=head2 print_dir |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
Print out the entire directory content to any opened file handle (the standard output by default): |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
$d64DiskDirObj->print_dir($fh); |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=cut |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
sub print_dir { |
388
|
2
|
|
|
2
|
1
|
811
|
my $self = shift; |
389
|
2
|
|
|
|
|
3
|
my $fh = shift; |
390
|
2
|
100
|
|
|
|
7
|
$fh = *STDOUT unless defined $fh; |
391
|
2
|
|
|
|
|
5
|
$self->_check_dir_read(); |
392
|
2
|
|
|
|
|
5
|
$self->_print_title($fh); |
393
|
2
|
|
|
|
|
24
|
my $num_entries = $self->num_entries(); |
394
|
2
|
|
|
|
|
5
|
for (my $i = 0; $i < $num_entries; $i++) { |
395
|
6
|
|
|
|
|
36
|
my $entryObj = $self->get_entry($i); |
396
|
6
|
|
|
|
|
14
|
$entryObj->print_entry($fh); |
397
|
|
|
|
|
|
|
} |
398
|
2
|
|
|
|
|
17
|
$self->_print_blocks_free($fh); |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
sub _print_title { |
402
|
2
|
|
|
2
|
|
3
|
my $self = shift; |
403
|
2
|
|
|
|
|
2
|
my $fh = shift; |
404
|
|
|
|
|
|
|
# Get title converted to ASCII: |
405
|
2
|
|
|
|
|
5
|
my $title = $self->get_title(1); |
406
|
|
|
|
|
|
|
# Get disk ID converted to ASCII: |
407
|
2
|
|
|
|
|
5
|
my $id = $self->get_id(1); |
408
|
|
|
|
|
|
|
# Print title and disk ID: |
409
|
2
|
|
|
|
|
30
|
printf $fh "0 \"%-16s\" %s\n", $title, $id; |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
sub _print_blocks_free { |
413
|
2
|
|
|
2
|
|
4
|
my $self = shift; |
414
|
2
|
|
|
|
|
3
|
my $fh = shift; |
415
|
|
|
|
|
|
|
# Print number of blocks free: |
416
|
2
|
|
|
|
|
5
|
my $blocksFree = $self->get_blocks_free(); |
417
|
2
|
|
|
|
|
18
|
printf $fh "%d blocks free\n", $blocksFree; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
sub DESTROY { |
421
|
26
|
|
|
26
|
|
7668
|
my $self = shift; |
422
|
26
|
|
|
|
|
49
|
$self->_release_d64_image(); |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
sub _release_d64_image { |
426
|
51
|
|
|
51
|
|
56
|
my $self = shift; |
427
|
51
|
|
|
|
|
67
|
my $d64DiskImageObj = $self->{'D64_DISK_IMAGE'}; |
428
|
51
|
|
|
|
|
66
|
delete $self->{'D64_DISK_IMAGE'}; |
429
|
|
|
|
|
|
|
# Release D64 image: |
430
|
51
|
100
|
|
|
|
249
|
$d64DiskImageObj->free_image() if defined $d64DiskImageObj; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=head1 BUGS |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
There are no known bugs at the moment. Please report any bugs or feature requests. |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=head1 EXPORT |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
None. No method is exported into the caller's namespace either by default or explicitly. |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=head1 SEE ALSO |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
L, L, L |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
=head1 AUTHOR |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
Pawel Krol, Epawelkrol@cpan.orgE. |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head1 VERSION |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
Version 0.04 (2018-11-25) |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
This module is licensed under a slightly modified BSD license, the same terms as Per Olofsson's "diskimage.c" library and L Perl package it is based on, license contents are repeated below. |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Copyright (c) 2003-2006, Per Olofsson |
458
|
|
|
|
|
|
|
All rights reserved. |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
=over |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
=item * |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
=item * |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=back |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
diskimage.c website: L |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=cut |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
1; |