File Coverage

blib/lib/D64/Disk/Layout/Sector.pm
Criterion Covered Total %
statement 236 239 98.7
branch 110 112 98.2
condition 31 39 79.4
subroutine 28 29 96.5
pod 12 14 85.7
total 417 433 96.3


line stmt bran cond sub pod time code
1             package D64::Disk::Layout::Sector;
2              
3             =head1 NAME
4              
5             D64::Disk::Layout::Sector - An abstraction layer over physical sector data of various Commodore disk image formats
6              
7             =head1 SYNOPSIS
8              
9             use D64::Disk::Layout::Sector;
10              
11             # Create a new disk sector object instance:
12             my $object = D64::Disk::Layout::Sector->new(data => $data, track => $track, sector => $sector);
13             my $object = D64::Disk::Layout::Sector->new(data => \@data, track => $track, sector => $sector);
14              
15             # Fetch sector data as a scalar of 256 bytes:
16             my $data = $object->data();
17             # Fetch sector data as an array of 256 bytes:
18             my @data = $object->data();
19              
20             # Update sector providing 256 bytes of scalar data:
21             $object->data($data);
22             # Update sector given array with 256 bytes of data:
23             $object->data(@data);
24             $object->data(\@data);
25              
26             # Fetch the actual file contents from sector data as a scalar of allocated number of bytes:
27             my $file_data = $object->file_data();
28             # Fetch the actual file contents from sector data as an array of allocated number of bytes:
29             my @file_data = $object->file_data();
30              
31             # Update the actual file contents providing number of scalar data bytes to allocate:
32             $object->file_data($file_data);
33             # Update the actual file contents given array with number of bytes of data to allocate:
34             $object->file_data(@file_data);
35             $object->file_data(\@file_data);
36              
37             # Get/set track location of the object data in the actual disk image:
38             my $track = $object->track();
39             $object->track($track);
40              
41             # Get/set sector location of the object data in the actual disk image:
42             my $sector = $object->sector();
43             $object->sector($sector);
44              
45             # Check if first two bytes of data point to the next chunk of data in a chain:
46             my $is_valid_ts_link = $object->is_valid_ts_link();
47              
48             # Get/set track and sector link values to the next chunk of data in a chain:
49             my ($track, $sector) = $object->ts_link();
50             $object->ts_link($track, $sector);
51              
52             # Check if first two bytes of data indicate index of the last allocated byte:
53             my $is_last_in_chain = $object->is_last_in_chain();
54              
55             # Get/set index of the last allocated byte within the sector data:
56             my $alloc_size = $object->alloc_size();
57             $object->alloc_size($alloc_size);
58              
59             # Check if sector object is empty:
60             my $is_empty = $object->empty();
61              
62             # Set/clear boolean flag marking sector object as empty:
63             $object->empty($empty);
64              
65             # Wipe out an entire sector data, and mark it as empty:
66             $object->clean();
67              
68             # Print out formatted disk sector data:
69             $object->print();
70              
71             =head1 DESCRIPTION
72              
73             C provides a helper class for C module and defines an abstraction layer over physical sector data of various Commodore disk image formats, enabling users to access and modify disk sector data in an object oriented way without the hassle of worrying about the meaning of individual bits and bytes, describing their function in a disk image layout. The whole family of C modules has been implemented in pure Perl as an alternative to Per Olofsson's "diskimage.c" library originally written in an ANSI C.
74              
75             =head1 METHODS
76              
77             =cut
78              
79 6     6   496159 use bytes;
  6         70  
  6         32  
80 6     6   195 use strict;
  6         14  
  6         196  
81 6     6   6509 use utf8;
  6         70  
  6         35  
82 6     6   213 use warnings;
  6         11  
  6         375  
83              
84             our $VERSION = '0.02';
85              
86 6     6   6371 use Data::Dumper;
  6         43262  
  6         505  
87 6     6   5820 use Readonly;
  6         21250  
  6         369  
88 6     6   7216 use Storable qw(dclone);
  6         25268  
  6         498  
89 6     6   6199 use Text::Convert::PETSCII qw/:convert/;
  6         17763  
  6         8340  
90              
91             require XSLoader;
92             XSLoader::load(__PACKAGE__, $VERSION);
93              
94             # Data offset constants:
95             Readonly our $I_TS_POINTER_TRACK => 0x00;
96             Readonly our $I_TS_POINTER_SECTOR => 0x01;
97             Readonly our $I_ALLOC_SIZE => 0x01;
98             Readonly our $I_SECTOR_DATA => 0x02;
99              
100             Readonly our $SECTOR_DATA_SIZE => 0x0100;
101              
102             =head2 new
103              
104             Create an instance of a C class as an empty disk sector:
105              
106             my $object = D64::Disk::Layout::Sector->new();
107              
108             Create an instance of a C class providing 256 bytes of data retrieved from a disk image:
109              
110             my $object = D64::Disk::Layout::Sector->new(data => $data, track => $track, sector => $sector);
111             my $object = D64::Disk::Layout::Sector->new(data => \@data, track => $track, sector => $sector);
112              
113             C<$track> and C<$sector> values are expected to be single bytes, an exception will be thrown when non-byte or non-numeric or non-scalar value is provided (please note that a default value of C is internally translated into the value of C<0x00>). For more information about C<$data> and C<@data> validation, see the C section below.
114              
115             =cut
116              
117             sub new {
118 167     167 1 317891 my ($this, %args) = @_;
119 167   33     2095 my $class = ref ($this) || $this;
120 167         523 my $object = $class->_init();
121 167         515 my $self = bless $object, $class;
122              
123 167 100       657 if (%args) {
124 126 100       371 unless (defined $args{data}) {
125 2         9 die sprintf q{Unable to initialize sector data: undefined value of data (%d bytes expected)}, $SECTOR_DATA_SIZE;
126             }
127 124 100       290 unless (defined $args{track}) {
128 1         23 die q{Unable to initialize track property: undefined value of track (numeric value expected)};
129             }
130 123 100       276 unless (defined $args{sector}) {
131 1         22 die q{Unable to initialize sector property: undefined value of sector (numeric value expected)};
132             }
133              
134 122         419 $self->data($args{data});
135 113         436 $self->track($args{track});
136 109         336 $self->sector($args{sector});
137             }
138              
139 147         594 return $self;
140             }
141              
142             sub _init {
143 168     168   273 my ($this) = @_;
144 168         848 my @data = map { chr 0x00 } (0x01 .. $SECTOR_DATA_SIZE);
  43008         56191  
145 168         2819 my %object = (
146             data => \@data,
147             track => 0,
148             sector => 0,
149             is_empty => 1,
150             );
151 168         486 return \%object;
152             }
153              
154             sub _object_property {
155 1666     1666   2241 my ($self, $name, $value) = @_;
156              
157 1666 100       2891 if (defined $value) {
158 548 100       25137 $self->{$name} = ref $value ? dclone $value : $value;
159             }
160              
161 1666         5649 return $self->{$name};
162             }
163              
164             sub _is_valid_byte_value {
165 34059     34059   46064 my ($self, $byte_value) = @_;
166              
167 34059 50 100     253056 if (defined $byte_value && length ($byte_value) == 1 && ord ($byte_value) >= 0x00 && ord ($byte_value) <= 0xff) {
      66        
      66        
168 34051         122839 return 1;
169             }
170              
171 8         21 return 0;
172             }
173              
174             sub _is_valid_number_value {
175 279     279   337 my ($self, $number_value) = @_;
176              
177 279 100 66     570 if ($self->is_int($number_value) && $number_value >= 0x00 && $number_value <= 0xff) {
      100        
178 234         1267 return 1;
179             }
180              
181 45         123 return 0;
182             }
183              
184             =head2 data
185              
186             Fetch sector data as a scalar of 256 bytes:
187              
188             my $data = $object->data();
189              
190             Fetch sector data as an array of 256 bytes:
191              
192             my @data = $object->data();
193              
194             Update sector providing 256 bytes of scalar data retrieved from a disk image:
195              
196             $object->data($data);
197              
198             C<$data> value is expected to be a scalar of 256 bytes in length, an exception will be thrown when non-scalar value or a scalar which does not have a length of 256 bytes or a scalar which contains wide non-byte character is provided.
199              
200             Update sector given array with 256 bytes of data retrieved from a disk image:
201              
202             $object->data(@data);
203             $object->data(\@data);
204              
205             C<@data> value is expected to be an array of 256 bytes in size, an exception will be thrown when non-array or an array with any other number of elements or an array with non-scalar byte values is provided.
206              
207             =cut
208              
209             sub data {
210 180     180 1 9602 my ($self, @args) = @_;
211              
212 180         565 my $data = $self->_validate_data(args => \@args, min_size => $SECTOR_DATA_SIZE, max_size => $SECTOR_DATA_SIZE, what => 'sector');
213              
214 152 100       429 if (defined $data) {
215 124         442 $self->_object_property('data', $data);
216              
217             # When data is set, object is no longer empty (unless it's filled with zeroes)
218 124         440 my $is_valid_ts_link = $self->is_valid_ts_link();
219 124         372 my $alloc_size = $self->alloc_size();
220 124 100 100     468 unless ($is_valid_ts_link || $alloc_size != 0) {
221 4         14 $self->empty(1);
222             }
223             else {
224 120         340 $self->empty(0);
225             }
226             }
227              
228 152 100       2309 return unless defined wantarray;
229              
230 28         62 $data = $self->_object_property('data');
231              
232 28 100       64 return wantarray ? @{$data} : join '', @{$data};
  13         735  
  15         227  
233             }
234              
235             sub _validate_data {
236 220     220   1238 my ($self, %args) = @_;
237              
238 220         1570 my @args = @{$args{args}};
  220         794  
239              
240 220 100       613 return unless scalar @args > 0;
241              
242             # Convert arrayref parameter to an array:
243 192 100       459 if (scalar @args == 1) {
244 182         258 my ($arg) = @args;
245 182 100       514 if (ref $arg eq 'ARRAY') {
246 149         168 @args = @{$arg};
  149         8772  
247             }
248             }
249              
250 192         1271 my $what = $args{what};
251 192         292 my $min_size = $args{min_size};
252 192         252 my $max_size = $args{max_size};
253              
254             # Convert scalar parameter to an array:
255 192 100       418 if (scalar @args == 1) {
256 34         49 my ($arg) = @args;
257 34 100       76 unless (ref $arg) {
258 6     6   65 no bytes;
  6         19  
  6         56  
259 31 100 100     145 if (length ($arg) < $min_size || length ($arg) > $max_size) {
260 8         115 die sprintf q{Unable to set %s data: Invalid length of data}, $what;
261             }
262 23         485 @args = split //, $arg;
263             }
264             else {
265 3         54 die sprintf q{Unable to set %s data: Invalid arguments given}, $what;
266             }
267             }
268              
269 181 100 100     942 unless (scalar (@args) < $min_size || scalar (@args) > $max_size) {
270 170         444 for (my $i = 0; $i < @args; $i++) {
271 34063         61178 my $byte_value = $args[$i];
272 34063 100       62125 if (ref $byte_value) {
273 4         121 die sprintf q{Unable to set %s data: Invalid data type at offset %d (%s)}, $what, $i, ref $args[$i];
274             }
275 34059 100       58841 unless ($self->_is_valid_byte_value($byte_value)) {
276 8         30 die sprintf q{Unable to set %s data: Invalid byte value at offset %d (%s)}, $what, $i, $self->_dump($byte_value);
277             }
278             }
279             }
280             else {
281 11         274 die sprintf q{Unable to set %s data: Invalid amount of data}, $what;
282             }
283              
284 158         7077 my @data = @args;
285              
286 158         15324 return \@data;
287             }
288              
289             =head2 file_data
290              
291             Fetch the actual file contents from sector data as a scalar of allocated number of bytes:
292              
293             my $file_data = $object->file_data();
294              
295             Fetch the actual file contents from sector data as an array of allocated number of bytes:
296              
297             my @file_data = $object->file_data();
298              
299             Update the actual file contents providing number of scalar data bytes to allocate:
300              
301             $object->file_data($file_data, set_alloc_size => $set_alloc_size);
302              
303             C<$file_data> value is expected to be a scalar of between 0 and 254 bytes in length, an exception will be thrown when non-scalar value or a scalar which does not have a length between 0 and 254 bytes or a scalar which contains wide non-byte character is provided. C<$set_alloc_size> input parameter defaults to C<0>. That means every file data assignment modifies only certain data bytes. This may or may not be a desired behaviour. If C<$file_data> contains 254 bytes of data, it is likely that the first two bytes of sector data should still point to the next chunk of data in a chain and thus remain unchanged. If C<$set_alloc_size> flag is set, this operation will additionally mark sector object as the last sector in chain and calculate the last allocated byte within sector data based on the number of bytes provided in C<$file_data> value. This value will then be assigned to the C object property.
304              
305             Update the actual file contents given array with number of bytes of data to allocate:
306              
307             $object->file_data(\@file_data, set_alloc_size => $set_alloc_size);
308              
309             C<@file_data> value is expected to be an array of between 0 and 254 bytes in size, an exception will be thrown when non-array or an array with any other number of elements not in between 0 and 254 or an array with non-scalar byte values is provided. C<$set_alloc_size> input parameter defaults to C<0>. The same remarks apply here as the ones desribed in a paragraph above.
310              
311             =cut
312              
313             sub file_data {
314 56     56 1 4922 my ($self, $data, %args) = @_;
315              
316 56 100       167 $args{set_alloc_size} = 0 if not exists $args{set_alloc_size};
317              
318 56 100       197 my $file_data = $self->_validate_data(args => [$data], min_size => 0, max_size => 254, what => 'file') if defined $data;
319              
320 50 100       116 if (defined $file_data) {
321 34         35 my $file_data_size = scalar @{$file_data};
  34         46  
322              
323 34         69 my $data = $self->_object_property('data');
324 34         39 splice @{$data}, $I_SECTOR_DATA, $file_data_size, @{$file_data};
  34         45  
  34         125  
325              
326 34 100       608 if ($args{set_alloc_size}) {
327 12         31 $data->[$I_TS_POINTER_TRACK] = chr 0x00;
328 12 100       84 $data->[$I_ALLOC_SIZE] = chr ($file_data_size + ($file_data_size > 0x00 ? 0x01 : 0x00));
329             }
330              
331 34         97 $self->_object_property('data', $data);
332              
333             # When data is set, object is no longer empty (unless it's filled with zeroes)
334 34         71 my $is_valid_ts_link = $self->is_valid_ts_link();
335 34         65 my $alloc_size = $self->alloc_size();
336 34 100 100     116 unless ($is_valid_ts_link || $alloc_size != 0) {
337 11         23 $self->empty(1);
338             }
339             else {
340 23         46 $self->empty(0);
341             }
342             }
343              
344 50 100       282 return unless defined wantarray;
345              
346 16         27812 $data = $self->_object_property('data');
347              
348 16         27 my @file_data = @{$data};
  16         662  
349 16         50 my $alloc_size = $self->alloc_size();
350              
351 16         179 splice @file_data, $alloc_size + 1;
352 16         47 splice @file_data, 0, $I_SECTOR_DATA;
353              
354 16 100       418 return wantarray ? @file_data : join '', @file_data;
355             }
356              
357             =head2 track
358              
359             Get track location of sector data in the actual disk image:
360              
361             my $track = $object->track();
362              
363             Set track location of sector data in the actual disk image:
364              
365             $object->track($track);
366              
367             C<$track> value is expected to be a single byte, an exception will be thrown when non-byte or non-numeric or non-scalar value is provided.
368              
369             =cut
370              
371             sub track {
372 125     125 1 572 my ($self, $track) = @_;
373              
374 125 100       323 if (defined $track) {
375 118 100       246 if (ref $track) {
376 2         13 die sprintf q{Invalid type (%s) of track location of sector data (single byte expected)}, $self->_dump($track);
377             }
378 116 100       313 unless ($self->_is_valid_number_value($track)) {
379 4         13 die sprintf q{Invalid value (%s) of track location of sector data (single byte expected)}, $self->_dump($track);
380             }
381 112 100       259 if ($track == 0x00) {
382 1         25 die sprintf q{Illegal value (0) of track location of sector data (track 0 does not exist)};
383             }
384 111         300 $track = $self->_object_property('track', $track);
385             }
386              
387 118         341 $track = $self->_object_property('track');
388              
389 118         199 return $track;
390             }
391              
392             =head2 sector
393              
394             Get sector location of sector data in the actual disk image:
395              
396             my $sector = $object->sector();
397              
398             Set sector location of sector data in the actual disk image:
399              
400             $object->sector($sector);
401              
402             C<$sector> value is expected to be a single byte, an exception will be thrown when non-byte or non-numeric or non-scalar value is provided.
403              
404             =cut
405              
406             sub sector {
407 121     121 1 498 my ($self, $sector) = @_;
408              
409 121 100       281 if (defined $sector) {
410 114 100       222 if (ref $sector) {
411 2         9 die sprintf q{Invalid type (%s) of sector location of sector data (single byte expected)}, $self->_dump($sector);
412             }
413 112 100       244 unless ($self->_is_valid_number_value($sector)) {
414 4         18 die sprintf q{Invalid value (%s) of sector location of sector data (single byte expected)}, $self->_dump($sector);
415             }
416 108         1062 $sector = $self->_object_property('sector', $sector);
417             }
418              
419 115         250 $sector = $self->_object_property('sector');
420              
421 115         349 return $sector;
422             }
423              
424             =head2 is_valid_ts_link
425              
426             Check if first two bytes of data point to the next chunk of data in a chain:
427              
428             my $is_valid_ts_link = $object->is_valid_ts_link();
429              
430             =cut
431              
432             sub is_valid_ts_link {
433 378     378 1 537 my ($self) = @_;
434              
435 378         656 my $data = $self->_object_property('data');
436              
437 378         1516 my $ts_pointer_track = ord $data->[$I_TS_POINTER_TRACK];
438              
439 378 100       2487 return $ts_pointer_track == 0x00 ? 0 : 1;
440             }
441              
442             =head2 ts_link
443              
444             Get track and sector link values to the next chunk of data in a chain:
445              
446             my ($track, $sector) = $object->ts_link();
447              
448             Track and sector values will be returned if first two bytes of data point to the next chunk of data in a chain, indicating this sector is in a link chain. When two first bytes of data indicate an index of the last allocated byte, an undefined value will be returned. An undefined value indicates that this is the last sector in a chain (and C can be used to fetch index of the last allocated byte within sector data).
449              
450             Set track and sector link values to the next chunk of data in a chain:
451              
452             $object->ts_link($track, $sector);
453              
454             Setting track/sector link includes sector in a chain and adds link to the next sector of data, at the same time allocating an entire sector for storing file data.
455              
456             =cut
457              
458             sub ts_link {
459 24     24 1 4814 my ($self, $track, $sector) = @_;
460              
461 24         69 my $data = $self->_object_property('data');
462              
463 24 100 100     103 if (defined $track || defined $sector) {
464 12 100       32 unless (defined $track) {
465 1         7 die sprintf q{Undefined value of track location for the next chunk of data in a chain (single byte expected)}, $self->_dump($track);
466             }
467 11 100       27 if (ref $track) {
468 1         5 die sprintf q{Invalid type (%s) of track location for the next chunk of data in a chain (single byte expected)}, $self->_dump($track);
469             }
470 10 100       25 unless ($self->_is_valid_number_value($track)) {
471 2         12 die sprintf q{Invalid value (%s) of track location for the next chunk of data in a chain (single byte expected)}, $self->_dump($track);
472             }
473 8 100       20 if ($track == 0x00) {
474 1         15 die sprintf q{Illegal value (0) of track location for the next chunk of data in a chain (track 0 does not exist)};
475             }
476              
477 7 100       18 unless (defined $sector) {
478 1         8 die sprintf q{Undefined value of sector location for the next chunk of data in a chain (single byte expected)}, $self->_dump($sector);
479             }
480 6 100       16 if (ref $sector) {
481 1         6 die sprintf q{Invalid type (%s) of sector location for the next chunk of data in a chain (single byte expected)}, $self->_dump($sector);
482             }
483 5 100       13 unless ($self->_is_valid_number_value($sector)) {
484 2         11 die sprintf q{Invalid value (%s) of sector location for the next chunk of data in a chain (single byte expected)}, $self->_dump($sector);
485             }
486              
487 3         16 $data->[$I_TS_POINTER_TRACK] = chr $track;
488 3         23 $data->[$I_TS_POINTER_SECTOR] = chr $sector;
489              
490             # Once valid track and sector link values are set, sector can no longer be considered empty:
491 3         18 $self->empty(0);
492             }
493              
494 15 100       37 return unless $self->is_valid_ts_link();
495              
496 11         27 $track = ord $data->[$I_TS_POINTER_TRACK];
497 11         65 $sector = ord $data->[$I_TS_POINTER_SECTOR];
498              
499 11         63 return ($track, $sector);
500             }
501              
502             *ts_pointer = \&ts_link;
503              
504             =head2 is_last_in_chain
505              
506             Check if two first bytes of data indicate an index of the last allocated byte, meaning this is the last sector in a chain:
507              
508             my $is_last_in_chain = $object->is_last_in_chain();
509              
510             Note that C method will always correctly return index of the last allocated byte within the sector data (even if first two bytes of data contain track and sector link values to the next chunk of data in a chain).
511              
512             =cut
513              
514             sub is_last_in_chain {
515 14     14 1 113 my ($self) = @_;
516              
517 14         30 my $data = $self->_object_property('data');
518              
519 14         46 my $ts_pointer_track = ord $data->[$I_TS_POINTER_TRACK];
520              
521 14 100       89 return $ts_pointer_track == 0x00 ? 1 : 0;
522             }
523              
524             =head2 alloc_size
525              
526             Get index of the last allocated byte within the sector data:
527              
528             my $alloc_size = $object->alloc_size();
529              
530             Index of the last valid (loaded) file byte will be returned when this is the last sector in a chain. When C<0xff> value is returned, this sector may be included in a link chain (if that is the case, C can be used to fetch track and sector link values to the next chunk of data in a chain).
531              
532             Set index of the last allocated byte within the sector data:
533              
534             $object->alloc_size($alloc_size);
535              
536             Setting index of the last allocated byte marks sector as the last one in a chain.
537              
538             =cut
539              
540             sub alloc_size {
541 194     194 1 667 my ($self, $alloc_size) = @_;
542              
543 194         360 my $data = $self->_object_property('data');
544              
545 194 100       424 if (defined $alloc_size) {
546 6 100       16 if (ref $alloc_size) {
547 1         6 die sprintf q{Invalid index type (%s) of the last allocated byte within the sector data (single byte expected)}, $self->_dump($alloc_size);
548             }
549 5 100       15 unless ($self->_is_valid_number_value($alloc_size)) {
550 2         41 die sprintf q{Invalid index value (%s) of the last allocated byte within the sector data (single byte expected)}, $self->_dump($alloc_size);
551             }
552 3         12 $data->[$I_ALLOC_SIZE] = chr $alloc_size;
553 3         19 $data->[$I_TS_POINTER_TRACK] = chr 0x00;
554             }
555              
556 191 100       377 return 0xff if $self->is_valid_ts_link();
557              
558 75         279 $alloc_size = ord $data->[$I_ALLOC_SIZE];
559              
560 75         325 return $alloc_size;
561             }
562              
563             =head2 empty
564              
565             Check if sector object is empty:
566              
567             my $is_empty = $object->empty();
568              
569             Set boolean flag to mark sector object as empty:
570              
571             $object->empty(1);
572              
573             Clear boolean flag to mark sector object as non-empty:
574              
575             $object->empty(0);
576              
577             =cut
578              
579             sub empty {
580 195     195 1 586 my ($self, $is_empty) = @_;
581              
582 195 100       388 if (defined $is_empty) {
583 168 100       322 if (ref $is_empty) {
584 1         21 die q{Invalid "empty" flag};
585             }
586 167 100       454 $self->_object_property('is_empty', $is_empty ? 1 : 0);
587             }
588              
589 194         379 $is_empty = $self->_object_property('is_empty');
590              
591 194         866 return $is_empty;
592             }
593              
594             =head2 clean
595              
596             Wipe out an entire sector data, and mark it as empty:
597              
598             $object->clean();
599              
600             =cut
601              
602             sub clean {
603 1     1 1 23 my ($self) = @_;
604              
605 1         5 my $clean_object = $self->_init();
606              
607 1         3 while (my ($property, $value) = each %{$clean_object}) {
  5         16  
608 4         7 $self->_object_property($property, $value);
609             }
610              
611 1         20 return;
612             }
613              
614             =head2 print
615              
616             Print out formatted disk sector data:
617              
618             $object->print(fh => $fh);
619              
620             C<$fh> defaults to the standard output.
621              
622             =cut
623              
624             sub print {
625 3     3 1 275 my ($self, %args) = @_;
626              
627 3         6 my $fh = $args{fh};
628              
629 3   33     11 $fh ||= *STDOUT;
630 3         25 $fh->binmode(':bytes');
631              
632 3         20 my $stdout = select $fh;
633              
634 3         9 my $data = $self->_object_property('data');
635              
636 3         12 print q{ };
637 3         60 for (my $col = 0x00; $col < 0x10; $col++) {
638 48         457 printf q{%02X }, $col;
639             }
640 3         29 print qq{\n} . q{ } . '-' x 47 . qq{\n};
641 3         30 for (my $row = 0x00; $row < 0x100; $row += 0x10) {
642 48         437 printf q{%02X: }, $row;
643 48         426 for (my $col = 0x00; $col < 0x10; $col++) {
644 768         6823 my $val = ord $data->[$row + $col];
645 768         1470 printf q{%02X }, $val;
646             }
647 48         465 for (my $col = 0x00; $col < 0x10; $col++) {
648 768         6525 my $val = ord $data->[$row + $col];
649 768 100 66     1580 if ($val >= 0x20 and $val <= 0x7f) {
650 1         7 $val = ord petscii_to_ascii chr $val;
651             }
652             else {
653 767         780 $val = ord '?';
654             }
655 768         1566 printf q{%c}, $val;
656             }
657 48         466 printf qq{\n};
658             }
659              
660 3         34 select $stdout;
661              
662 3         11 return;
663             }
664              
665             sub _dump {
666 31     31   55 my ($self, $value) = @_;
667              
668 31 50       84 if ($self->_is_valid_number_value($value)) {
669 0         0 return sprintf q{$%02x}, $value;
670             }
671              
672 31         272 my $dump = Data::Dumper->new([$value])->Indent(0)->Terse(1)->Deepcopy(1)->Sortkeys(1)->Dump();
673              
674 31         4536 return $dump;
675             }
676              
677             sub is_int {
678 279     279 0 334 my ($this, $var) = @_;
679              
680 279         2006 return _is_int($var);
681             }
682              
683             sub is_str {
684 0     0 0   my ($this, $var) = @_;
685              
686 0           return _is_str($var);
687             }
688              
689             =head1 BUGS
690              
691             There are no known bugs at the moment. Please report any bugs or feature requests.
692              
693             =head1 EXPORT
694              
695             None. No method is exported into the caller's namespace neither by default nor explicitly.
696              
697             =head1 SEE ALSO
698              
699             L, L.
700              
701             =head1 AUTHOR
702              
703             Pawel Krol, Epawelkrol@cpan.orgE.
704              
705             =head1 VERSION
706              
707             Version 0.02 (2013-02-10)
708              
709             =head1 COPYRIGHT AND LICENSE
710              
711             Copyright 2013 by Pawel Krol Epawelkrol@cpan.orgE.
712              
713             This library is free open source software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.
714              
715             PLEASE NOTE THAT IT COMES WITHOUT A WARRANTY OF ANY KIND!
716              
717             =cut
718              
719             1;
720              
721             __END__