Convert-ASN1-asn1c
view release on metacpan or search on metacpan
lib/Convert/ASN1/asn1c.pm view on Meta::CPAN
$offset = $current_offset;
#count number of bytes in $value
$value_length = () = $value =~ /&#x..;/g;
#replace this line with the corrected values
$lines[$_] = "<P O=\"$offset\" T=\"$tag\" TL=\"$tag_length\" V=\"$value_length\"$rest)>$value</P>";
$current_offset += $tag_length;
$current_offset += $value_length;
}
if ($lines[$_] =~ m/<C O="(\d+)" T="(.+?)" TL="(\d+)" V="(\d+)"(.*?)>/) {
my $offset = $1;
my $tag = $2;
my $tag_length = $3;
my $value_length = $4;
my $rest = $5;
$offset = $current_offset;
#replace this line with the corrected values
$lines[$_] = "<C O=\"$offset\" T=\"$tag\" TL=\"$tag_length\" V=\"$value_length\"$rest)>";
$current_offset += $tag_length;
# put this line number on the stack, so that we can jump back here and fill in the value length once we know it
push @stack, $_;
}
if ($lines[$_] =~ m/<\/C O=\"(\d+)\" T=\"(.+?)\"(.+?)L=\"(\d+)\">/) {
my $offset = $1;
my $tag = $2;
my $rest = $3;
my $length = $4;
$offset = $current_offset;
my $opening_line = pop @stack;
if ($lines[$opening_line] =~ m/<C O="(\d+)" T="(.+?)" TL="(\d+)" V="(\d+)"(.*?)>/) {
my $op_offset = $1;
my $op_tag = $2;
my $op_tag_length = $3;
my $op_value_length = $4;
my $op_rest = $5;
$op_value_length = $current_offset - $op_offset - $op_tag_length;
$length = $current_offset - $op_offset;
$lines[$opening_line] = "<C O=\"$op_offset\" T=\"$op_tag\" TL=\"$op_tag_length\" V=\"$op_value_length\"$op_rest)>";
}
else {
die "Internal error, file bug report!\n";
}
#replace this line with the corrected values
$lines[$_] = "</C O=\"$current_offset\" T=\"$tag\"$rest L=\"$length\">";
}
}
$text = join("\n", @lines);
return $text;
}
=head2 $values = decode('pduname', $pdu);
The decode function takes the name of a template (the directory where to find
those templates can be modified with set_templatedir($dir)) and a binary pdu.
It will match the variables in the template against the decoded binary pdu and
return a reference to a hash which contains these values.
For each variable $myvalue the hash will contain four keys:
=head3 $values->{'myvalue'}
The decoded value if we could "guess" myvalues type because it was
specified as i.e. INTEGER or BIT STRING in the asn1 pdu.
=head3 $values->{'myvalue_orig'}
The original value as it was found in the unber -p output. Note that these
values are still xml-encoded. To decode them you can use this modules
decode_-functions or write your own decoders if the provided ones are not
sufficient.
=head3 $values->{'myvalue_length'}
The length of $myvalue as it was encoded in the asn1 pdu. This value is
needed for some _decode routines and can also be usefull if you write your own
decoder functions.
=head3 $values->{'myvalue_type'}
If the type of $myvalue is specified in the pdu, for example as INTEGER, this
key contains the value.
=cut
sub decode {
my ($self, $pduname, $pdu) = @_;
my @stack;
my @varpos;
# try to find the packet description
my @lines = read_file(File::Spec->catfile($self->{'_templatedir'}, $pduname));
# we will parse the packet description
# to find out which "nodes" in the tag tree are interesting for us
# and we will construct a list of those interesting nodes (and how to "reach" them,
# i.e. which parent nodes they are located under. In the second step we will
# iterate over the decoded ASN data, if we are in an inetersting leaf we will decode it's value.
foreach (@lines) {
if (m/<C .*?T=\"(.*?)\"/) { push @stack, $1; }
if (m/<\/C /) { pop @stack; }
if (m/<P .*?T=\"(.*?)\"/) { push @stack, $1; }
while (m/(\$.+?)("|<| |>)/gc) {
my $varname = $1;
if ($varname !~ m/_length$/) {
push(@varpos, $varname . ":" . join('|', @stack));
}
}
if (m/<\/P>/) { pop @stack; }
}
my @unber = qw( unber -p - );
my $text;
my $h = start \@unber, \$pdu, \$text;
pump $h while length $pdu;
finish $h or croak "unber returned $?";
@lines = qw();
@stack = qw();
@lines = split(/\n/, $text);
my %results;
foreach (@lines) {
my $line = $_;
if ($line =~ m/<C .*?T=\"(.*?)\"/) {
push @stack, $1;
}
if ($line =~ m/<\/C /) {
pop @stack;
}
if ($line =~ m/<P .*?T=\"(.*?)\"/) {
#check if this node is "interesting" - is there a entry in @varpos which matches the current stack
push @stack, $1;
my $current = join('|', @stack);
foreach (0 .. scalar(@varpos)-1) {
croak "Internal Parser error!\n" unless ($varpos[$_] =~ m/^\$(.*?):(.*?)$/);
my $varname = $1;
my $varposition = $2;
if ($varposition eq $current) {
# we are in an interesting node!
my $value = undef;
my $value_len = undef;
my $value_type = undef;
if ($line =~ m/ V=\"(.*?)\".*?>(.*?)</) {
$value_len = $1;
$value = $2;
if ($line =~ m/A=\"(.*?)\"/) { $value_type = $1; }
else { $value_type = 'UNDEFINED'; }
$results{$varname . '_length'} = $value_len;
$results{$varname . '_type'} = $value_type;
$results{$varname} = $value;
$results{$varname . '_orig'} = $value;
# remove the filled varpos entry
$varpos[$_] .= '--matched--';
last;
}
}
lib/Convert/ASN1/asn1c.pm view on Meta::CPAN
}
}
# now we have all interesting values in the results hash, together with
# their type (BE CAREFULL - "Siemens Bitstrings" have the type UNDEFINED)
# and length.
foreach (keys %results) {
my $key = $_;
if ($key !~ m/(_length$|_type$|_orig$)/) {
my $value = $results{$key};
my $type = $results{$key . '_type'};
my $length = $results{$key . '_length'};
if ($type eq 'OCTET STRING') {
$results{$key} = decode_octet_string($self, $value, $length);
}
if ($type eq 'INTEGER') {
$results{$key} = decode_integer($self, $value, $length);
}
if ($type =~ m/(BIT STRING)/) {
$results{$key} = decode_bitstring($self, $value, $length);
}
if ($type eq "GeneralizedTime") {
$results{$key} = decode_timestamp($self, $value, $length);
}
if ($type eq "ENUMERATED") {
# of course not all enumerated types are int's but
# in our context it seems to be a good guess
$results{$key} = decode_integer($self, $value, $length);
}
}
}
return \%results;
}
=head2 $values = sdecode($xml_template, $pdu);
The sdecode function takes a template and a binary pdu. It works the same way
as the decode function, but it directly takes the template as it's first
argument instead of a filename.
=cut
sub sdecode {
my ($self, $xml_template, $pdu) = @_;
my @stack;
my @varpos;
# try to find the packet description
my @lines = split(/\n/, $xml_template);
# we will parse the packet description
# to find out which "nodes" in the tag tree are interesting for us
# and we will construct a list of those interesting nodes (and how to "reach" them,
# i.e. which parent nodes they are located under. In the second step we will
# iterate over the decoded ASN data, if we are in an inetersting leaf we will decode it's value.
foreach (@lines) {
if (m/<C .*?T=\"(.*?)\"/) { push @stack, $1; }
if (m/<\/C /) { pop @stack; }
if (m/<P .*?T=\"(.*?)\"/) { push @stack, $1; }
while (m/(\$.+?)("|<| |>)/gc) {
my $varname = $1;
if ($varname !~ m/_length$/) {
push(@varpos, $varname . ":" . join('|', @stack));
}
}
if (m/<\/P>/) { pop @stack; }
}
my @unber = qw( unber -p - );
my $text;
my $h = start \@unber, \$pdu, \$text;
pump $h while length $pdu;
finish $h or croak "unber returned $?";
@lines = qw();
@stack = qw();
@lines = split(/\n/, $text);
my %results;
foreach (@lines) {
my $line = $_;
if ($line =~ m/<C .*?T=\"(.*?)\"/) {
push @stack, $1;
}
if ($line =~ m/<\/C /) {
pop @stack;
}
if ($line =~ m/<P .*?T=\"(.*?)\"/) {
#check if this node is "interesting" - is there a entry in @varpos which matches the current stack
push @stack, $1;
my $current = join('|', @stack);
foreach (0 .. scalar(@varpos)-1) {
croak "Internal Parser error!\n" unless ($varpos[$_] =~ m/^\$(.*?):(.*?)$/);
my $varname = $1;
my $varposition = $2;
if ($varposition eq $current) {
# we are in an interesting node!
my $value = undef;
my $value_len = undef;
my $value_type = undef;
if ($line =~ m/ V=\"(.*?)\".*?>(.*?)</) {
$value_len = $1;
$value = $2;
if ($line =~ m/A=\"(.*?)\"/) { $value_type = $1; }
else { $value_type = 'UNDEFINED'; }
$results{$varname . '_length'} = $value_len;
$results{$varname . '_type'} = $value_type;
$results{$varname} = $value;
$results{$varname . '_orig'} = $value;
# remove the filled varpos entry
$varpos[$_] .= '--matched--';
last;
}
}
( run in 0.976 second using v1.01-cache-2.11-cpan-995e09ba956 )