File Coverage

blib/lib/ESPPlus/Storage/Reader.pm
Criterion Covered Total %
statement 54 60 90.0
branch 8 16 50.0
condition 3 6 50.0
subroutine 11 11 100.0
pod 3 4 75.0
total 79 97 81.4


line stmt bran cond sub pod time code
1             package ESPPlus::Storage::Reader;
2 6     6   108 use 5.006;
  6         18  
  6         244  
3 6     6   29 use strict;
  6         13  
  6         182  
4 6     6   55 use warnings;
  6         12  
  6         191  
5 6     6   31 use Carp 'confess';
  6         13  
  6         336  
6 6     6   40 use ESPPlus::Storage::Util;
  6         88  
  6         292  
7              
8 6         1079 use vars qw($COMPRESS_MAGIC_NUMBER
9             $BLOCK_SIZE
10             $MAX_BUFFER_SIZE
11 6     6   36 $MIN_BUFFER_SIZE);
  6         10  
12              
13             $COMPRESS_MAGIC_NUMBER = "\037\235";
14              
15             #our $BASE_RECORD =
16             # q[(?x:
17             # \\A # Start at the beginning
18             #
19             # ((?xs:.+?))
20             # # Capture the .Z binary record. It is known to be $L characters
21             # # uncompressed so I'm using 0 -> $L as the size restriction.
22             #
23             # # Insert a tail condition here. Either match the next header or
24             # # the end of string if the buffer and file are exhausted.
25             # )];
26             #
27             #our $CONTINUED_RECORD =
28             # do {
29             # use re 'eval';
30             # qr( $BASE_RECORD
31             # # Find the header for the next section but don't remove it.
32             # H=(\d+);
33             # # The number after H indicates how many bytes the header is. The
34             # # expression should now look for $+ - length("H=$+;") characters
35             # # that match [[:print:]] followed by a .Z magic number or the
36             # # end of the string if the source filehandle is at eof().
37             #
38             # (??{ "(?s:.{".($+ - length "H=$+;")."})$COMPRESS_MAGIC_NUMBER" })
39             # )x;
40             # };
41             #
42             #our $LAST_RECORD = qr[$BASE_RECORD\z];
43              
44             $BLOCK_SIZE = 2 ** 13;
45             $MAX_BUFFER_SIZE = 128 * $BLOCK_SIZE;
46             $MIN_BUFFER_SIZE = 8 * $BLOCK_SIZE;
47              
48              
49             BEGIN {
50 6     6   17 for (qw(handle
51             record_number)) {
52 12         37 attribute_builder( $_, 'read only' );
53             }
54            
55 6         33 attribute_builder( 'uncompress_function' );
56             }
57              
58             sub new {
59 3     3 1 1131 my $class = shift;
60 3         7 my $p = shift;
61 3         15 my $self = bless {}, $class;
62            
63 3         27 $self->{'record_number'} = 0;
64 3         9 my $_buffer = '';
65 3         10 $self->{'_buffer'} = \ $_buffer;
66              
67 3         11 for my $param (qw[uncompress_function
68             handle]) {
69 6 50       30 unless ( exists $p->{$param} ) {
70 0         0 confess "Required parameter $param wasn't provided";
71             }
72            
73 6         23 $self->{$param} = delete $p->{$param};
74             }
75            
76 3         18 return $self;
77             }
78              
79             sub buffer {
80 3     3 0 6 my $self = shift;
81 3         7 my $handle = $self->{'handle'};
82 3         5 my $buffer = $self->{'_buffer'};
83              
84 3 50 66     88 if ( eof $handle and not length $$buffer ) {
85 0         0 return;
86             }
87            
88 3 50       13 if (length $$buffer < $MIN_BUFFER_SIZE) {
89 3         91 my $read_bytes = int
90             ( ($MAX_BUFFER_SIZE - length($$buffer))
91             / $BLOCK_SIZE ) * $BLOCK_SIZE;
92            
93 3         81 read( $handle,
94             $$buffer,
95             $read_bytes,
96             length $$buffer );
97             }
98            
99 3         9 return $buffer;
100             }
101              
102             sub next_record_body {
103 1     1 1 2 my $self = shift;
104              
105 1         7 my $record = $self->next_record;
106            
107 1 50       15 return $record->body if $record;
108 0         0 return;
109             }
110              
111             sub next_record {
112 2     2 1 4 my $self = shift;
113 2         9 my $buffer = $self->buffer;
114 2         7 my $rec_num = ++$self->{'record_number'};
115            
116 2 50       11 return unless $buffer;
117 2 50       32 unless ($$buffer =~ m/^H=(?>\d+);/) {
118 0         0 confess
119             "$rec_num was missing the header prefix m/^H=\\d+;/: $$buffer";
120             }
121            
122 2         18 my $header_length = substr $$buffer, 2, $+[0]-3;
123            
124             # Remove the header
125 2         12 my $header_text = substr $$buffer, 0, $header_length, '';
126            
127 2         3 my $record_body;
128 2 50 33     53 if ( $$buffer =~ /H=(?>\d+);/ and
    50          
129             $COMPRESS_MAGIC_NUMBER eq
130             substr( $$buffer,
131             $-[0] + substr($$buffer,$-[0]+2,$+[0]-$-[0]-3),
132             length($COMPRESS_MAGIC_NUMBER) ) ) {
133            
134             # Capture everything before the first header-looking thing.
135 0         0 $record_body = substr $$buffer, 0, $-[0], '';
136             } elsif ( eof $self->{'handle'} ) {
137            
138             # Since a header wasn't found, I'm expecting that the database is
139             # at the end.
140 2         4 $record_body = $$buffer;
141 2         4 $$buffer = '';
142             } else {
143            
144 0         0 confess("Er!");
145             }
146            
147             return
148 2         47 ESPPlus::Storage::Record->new
149             ( { header_text => \ $header_text,
150             compressed => \ $record_body,
151             uncompress_function => $self->{'uncompress_function'},
152             record_number => $rec_num } );
153             }
154              
155             1;
156              
157             __END__