package PGP::Unpackable;

use strict;

use Carp;

sub new {
    my ($class, $strref) = @_;

    bless {
	"strref" => $strref,
	"offset" => 0,
    };
}

sub strref {
    my ($self) = @_;

    $self->{"strref"};
}

sub offset {
    my ($self) = @_;

    $self->{"offset"};
}

sub remaining {
    my ($self) = @_;

    length(${$self->{"strref"}}) - $self->{"offset"};
}

sub unpack {
    my ($self, $unpackstr) = @_;

    my $length = length(pack($unpackstr));

    my ($offset, $strref) = @$self{"offset","strref"};

    if ($offset+$length > length($$strref)) {
	confess("unpack past end of string");
    }

    $self->{"offset"} += $length;

    unpack($unpackstr, substr($$strref, $offset, $length));
}

sub unpackC {
    my ($self) = @_;
    my ($offset, $strref) = @$self{"offset","strref"};

    if ($offset >= length($$strref)) {
	confess("unpackC past end of string");
    }

    $self->{"offset"}++;

    ord(substr($$strref,$offset,1));
}

sub unpacka {
    my ($self, $length) = @_;
    my ($offset, $strref) = @$self{"offset","strref"};

    if ($offset+$length > length($$strref)) {
	confess("unpacka past end of string");
    }

    $self->{"offset"} += $length;

    substr($$strref,$offset,$length);
}

sub skip {
    my ($self, $length) = @_;

    my ($offset, $strref) = @$self{"offset","strref"};

    if ($offset+$length > length($$strref)) {
	confess("skip past end of string");
    }

    $self->{"offset"} += $length;
}

sub unpack_mpi {
    my ($self) = @_;
    
    my $ret = {};

    $ret->{"length"} = $self->unpack("n");
    $ret->{"bits"} = $self->unpacka(int(($ret->{"length"}+7)/8));

    return($ret);
}

sub substr {
    my ($self, $start, $length) = @_;

    substr(${$self->{"strref"}}, $start, $length);
}

sub replace {
    my ($self, $start, $length, $data) = @_;

    my ($offset, $strref) = @$self{"offset","strref"};

    if (($start < $offset) && ($offset < ($start+$length))) {
	$self->{"offset"} = $start;
    } elsif ($offset >= ($start+$length)) {
	$self->{"offset"} += (length($data)-$length);
    }

    substr($ {$self->{"strref"}}, $start, $length) = $data;
}

sub remove {
    my ($self, $start, $length) = @_;

    $self->replace($start, $length, "");
}

1;
