# buffer size, in bytes use constant BUF_SIZE => 2048; # Constructed with a filename # sub new { my $filename = $_[0]; open(FH, "$filename") or die "$myname error: unable to open $filename: $!\n"; binmode(FH); my $filehandle = *FH; my $bytes_buf; my $bytes_read = read(*FH, $bytes_buf, BUF_SIZE); my $bits_buf = unpack("B*", $bytes_buf); # Members: # # FILENAME # FILEHANDLE # CUR_BUF - the current buffer held in memory (a bitstring) # CUR_BUF_LEN - length of the current buffer (in bits) # BUF_NUM - the first buffer in the file is 0, the next 1, and so on # BUF_POS - position inside the current buffer # my $self = {}; $self->{FILENAME} = $filename; $self->{FILEHANDLE} = $filehandle; $self->{CUR_BUF} = $bits_buf; $self->{CUR_BUF_LEN} = length($bits_buf); $self->{BUF_NUM} = 0; $self->{BUF_POS} = 0; print "$myname ($filename) created\n"; bless($self, $myname); } # Gets a specified amount of bits. Default is 1 # If the request is for more bits than left in the stream, returns the ones # left; an empty string is returned when the stream ends # sub get_bits { my $self = shift; my $howmany = (defined $_[0]) ? $_[0] : 1; my $ret_str = ""; ($howmany <= (BUF_SIZE * 8)) or die "Please read in chunks no longer than ", BUF_SIZE * 8, " bits\n"; my $n_bits_left_in_buf = $self->{CUR_BUF_LEN} - $self->{BUF_POS}; # the request is over the buffer's end ? if ($n_bits_left_in_buf < $howmany) { #~ print "$self->{CUR_BUF} $self->{BUF_POS} $n_bits_left_in_buf\n"; # take what's left in the buffer $ret_str = substr($self->{CUR_BUF}, $self->{BUF_POS}, $n_bits_left_in_buf); my $howmany_left = $howmany - $n_bits_left_in_buf; # read the next buffer my $bytes_buf; my $bytes_read = read($self->{FILEHANDLE}, $bytes_buf, BUF_SIZE); # was the current buffer the last in the file ? if (($self->{CUR_BUF_LEN} < BUF_SIZE * 8) or ($bytes_read == 0)) { # then we just read the last bits of the file. returning a string shorter # than $howmany signals to the caller that the stream ended # return $ret_str; } # update buffer info $self->{BUF_NUM} += 1; $self->{CUR_BUF} = unpack("B*", $bytes_buf); $self->{CUR_BUF_LEN} = $bytes_read * 8; #~ print "> $self->{CUR_BUF} $self->{CUR_BUF_LEN} $howmany_left\n"; # complete the read from the new buffer $ret_str .= substr($self->{CUR_BUF}, 0, $howmany_left); $self->{BUF_POS} = $howmany_left; } else # the request still fits the current buffer { $ret_str = substr($self->{CUR_BUF}, $self->{BUF_POS}, $howmany); $self->{BUF_POS} += $howmany; } return $ret_str; }