Hex-Record

 view release on metacpan or  search on metacpan

lib/Hex/Record.pm  view on Meta::CPAN

package Hex::Record;

use strict;
use warnings;
use Carp;

our $VERSION = '0.09';

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

    $args{parts} = [] unless exists $args{parts};

    return bless \%args, $class;
}

sub import_intel_hex {
    my ($self, $hex_string) = @_;

    my $addr_high_dec = 0;
    my $create_part = 0;
    for my $line (split m{\n\r?}, $hex_string) {
        my ($addr, $type, $bytes_str) = $line =~ m{
		  : # intel hex start
		   [[:xdigit:]]{2}  # bytecount
		  ([[:xdigit:]]{4}) # addr
		  ([[:xdigit:]]{2}) # type
		  ([[:xdigit:]] * ) # databytes
	       	   [[:xdigit:]]{2}  # checksum
	      }ix or next;

        my @bytes = unpack('(A2)*', $bytes_str);

        # data line?
        if ($type == 0) {
            $self->write($addr_high_dec + hex $addr, \@bytes, $create_part);
            $create_part = 0;
        }
        # extended linear address type?
        elsif ($type == 4) {
            $addr_high_dec = hex( join '', @bytes ) << 16;
            $create_part = 1;
        }
        # extended segment address type?
        elsif ($type == 2) {
            $addr_high_dec = hex( join '', @bytes ) << 4;
            $create_part = 1;
        }
    }

    return;
}

sub import_srec_hex {
    my ($self, $hex_string) = @_;

    my %address_length_of_srec_type = (
        0 => 4,
        1 => 4,
        2 => 6,
        3 => 8,
        4 => undef,
        5 => 4,
        6 => 6,
        7 => 8,
        8 => 6,
        9 => 4,
    );

    my @parts;
    for my $line (split m{\n\r?}, $hex_string) {
        next unless substr( $line, 0, 1 ) =~ m{s}i;

        my $type = substr $line, 1, 1;

        my $addr_length = $address_length_of_srec_type{$type} || next;

        my ($addr, $bytes_str) = $line =~ m{
		      s #srec hex start
		   [[:xdigit:]]{1}             #type
		   [[:xdigit:]]{2}              #bytecount
		  ([[:xdigit:]]{$addr_length})  #addr
		  ([[:xdigit:]] * )             #databytes
		   [[:xdigit:]]{2}              #checksum
	      }ix or next;

        # data line?
        if ($type == 1 || $type == 2 || $type == 3) {
            $self->write(hex $addr, [ unpack '(A2)*', $bytes_str ]);
        }
    }

    return;
}

sub write {
    my ($self, $from, $bytes_hex_ref, $create_part) = @_;
    $create_part ||= 0;

    $self->remove($from, scalar @$bytes_hex_ref);

    my $to = $from + @$bytes_hex_ref;

    for (my $part_i = 0; $part_i < @{ $self->{parts} }; $part_i++) {
        my $part = $self->{parts}->[$part_i];

        my $start_addr = $part->{start};
        my $end_addr   = $part->{start} + $#{ $part->{bytes} };

        # merge with this part
        if ($create_part == 0 && $to == $start_addr) {
            $part->{start} = $from;
            unshift @{ $part->{bytes} }, @$bytes_hex_ref;
            return;
        }
        elsif ($create_part == 0 && $from == $end_addr + 1) {
            push @{ $part->{bytes} }, @$bytes_hex_ref;

            return if $part_i+1 == @{ $self->{parts} };

            my $next_part = $self->{parts}->[$part_i+1];
            # merge with next part
            if ($to == $next_part->{start}) {
                push @{ $part->{bytes} }, @{ $next_part->{bytes} };
                splice @{ $self->{parts} }, $part_i+1, 1;
            }
            return;
        }
        elsif ($from < $start_addr) {
            splice @{ $self->{parts} }, $part_i, 0, {
                start => $from,



( run in 0.752 second using v1.01-cache-2.11-cpan-71847e10f99 )