<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#!/usr/bin/perl
#
#  $Id: hex2bin.pl,v 1.4 2004/07/04 08:44:48 jaalto Exp $
#
#  File id
#
#       .Copyright (C)  Jari Aalto
#       .Keywords:      Perl file conversion bin hex
#
#       This program is free software; you can redistribute it and/or
#       modify it under the terms of the GNU General Public License as
#       published by the Free Software Foundation; either version 2 of
#       the License, or (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful, but
#       WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#       General Public License for more details.
#
#       You should have received a copy of the GNU General Public License along
#       with this program; if not, write to the Free Software Foundation,
#       Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#   About program layout
#
#       Code written with Emacs and indentation controlled with
#       Emacs package tinytab.el, a generic tab minor mode for programming.
#
#       The {{ }}} marks you see in this file are party of file "fold"
#       control package called folding.el (Unix Emacs lisp package).
#
#   Change Log (none)

use 5.004;
use strict;

#       A U T O L O A D
#
#       The =&gt; operator quotes only words, and characte ':' is not
#       part of a Perl "word"

use autouse 'Pod::Text' =&gt; qw( pod2text );

#   Standard perl modules

use Env;
use English;
use File::Basename;
use Getopt::Long;

GLOBALS:
{
    use vars qw ( $VERSION );

    #   This is for use of Makefile.PL and ExtUtils::MakeMaker
    #   So that it puts the tardist number in format YYYY.MMDD
    #   The REAL version number is defined later

    #   The following variable is updated by Emacs setup whenever
    #   this file is saved

    $VERSION = '2004.1215';
}

# {{{ init

# ****************************************************************************
#
#   DESCRIPTION
#
#       Set global variables for the program
#
#   INPUT PARAMETERS
#
#       none
#
#   RETURN VALUES
#
#       none
#
# ****************************************************************************

sub Initialize ()
{
    use vars qw
    (
        $CONTACT
        $LIB
        $PROGNAME
        $RCS_ID
        $URL
        $VERSION
    );

    $LIB        = basename $PROGRAM_NAME;
    $PROGNAME   = $LIB;

    $RCS_ID   = '$Id: hex2bin.pl,v 1.4 2004/07/04 08:44:48 jaalto Exp $';
    $VERSION  = (split (' ', $RCS_ID))[2];   # version number in format N.NN+
    $CONTACT  = "";
    $URL      = "http://cpan.perl.org/modules/by-authors/id/J/JA/JARIAALTO/";

    $OUTPUT_AUTOFLUSH = 1;
}

# }}}
# {{{ Help

# ***************************************************************** &amp;help ****
#
#   DESCRIPTION
#
#       Print help and exit.
#
#   INPUT PARAMETERS
#
#       $msg    [optional] Reason why function was called.
#
#   RETURN VALUES
#
#       none
#
# ****************************************************************************

=pod

=head1 NAME

hex2bin.pl - Convert hex string file into binary file

=head1 SYNOPSIS

    hex2bin.pl --file out.bin input.hex
    hex2bin.pl --Eval 's,\.bin,\.hex,' input.hex

=head1 OPTIONS

=head2 General options

=over 4

=item B&lt;--beg-column COL&gt;

Ignore N characters from the beginning. Start reading at column COL.
Together with B&lt;--end-column&gt; you can slice the portion from the text file
E.g. if input contains constant indentation and garbage after column N.

=item B&lt;--end-column COL&gt;

Read until column COL and discard everything after that.

=item B&lt;-e|--extension EXTENSION&gt;

Append EXTENSION to each outputted file. Use along with B&lt;--File&gt; to change
the default extension

=item B&lt;-E|--Eval PERL-CODE&gt;

Evaluate PERL-CODE to make output the filename. The input filename is
in $ARG which you can modify with standard perl commands.

=item B&lt;-F|--File&gt;

Dump the binary to file with extension .bin

=item B&lt;-f|--file FILE&gt;

Dump the binary to FILE.

=item B&lt;-D|--input-decimal&gt;

Input data is represented in decimal format

=item B&lt;-H|--input-hex&gt;

Input data is represented in hex format. This the default.

=item B&lt;-O|--input-octal&gt;

Input data is represented in octal format

=item B&lt;--raw&gt;

Rip only the hex data from file and don't generate binary.

=back

=head2 Miscellaneous options

=over 4

=item B&lt;-d|--debug LEVEL&gt;

Turn on debug with positive LEVEL number. Zero means no debug.

=item B&lt;--help&gt; B&lt;-h&gt;

Print help page.

=item B&lt;--Version -V&gt;

Print program's version information.

=back

=head1 README

This program makes a binary file out of HEX input data. The default
input format is:

    XXXX: 00 00 01 01 01 # This is comment
    XXXX: 00 00 00 00 00   Deletes eveythinbg after 3 spaces

I.e. there must be line numbers at the beginning of hex lines.
The line numbers are stripped and the hex numbers are read to
form the file. Input can also be in this format

    8B/00/45/19/10/00/01/00/FF/35/49/44/58/16/17/03/
    00/07/39/17/00/0D/1E/09/60/13/FF/FF/FF/FF/6D/00/

This program is quite forgiving, any extra lines that don't look
like hexdump will be skipped, so you can have the data in following
format too and program will only pick the hexdump out of it.

    00000200  A3 03 AD B6 10 00 01 00 FF 35 49 44 58 01 04 05   .....
    00000210  00 07 19 21 05 09 13 0B 61 13 FF FF FF FF 85 03   ...!.

=head1 EXAMPLES

To output to a file that is derived from the filename

    hex2bin.pl --extension ".bin" fileh.hex # output to file.hex.bin

This changes all .hex names into .bin while composing the output filename:

    hex2bin.pl --Eval 's,\.hex,\.bin,' file.hex

To give explicit filename where output is put:

    hex2bin --file out.bin file.hex          # output to out.bin

=head1 ENVIRONMENT

No environment variables used.

=head1 SEE ALSO

od(1)

=head1 AVAILABILITY

CPAN entry is http://cpan.perl.org/modules/by-authors/id/J/JA/JARIAALTO/

=head1 SCRIPT CATEGORIES

CPAN/Administrative

=head1 PREREQUISITES

No CPAN modules required.

=head1 COREQUISITES

No optional CPAN modules needed.

=head1 OSNAMES

C&lt;any&gt;

=head1 VERSION

$Id: hex2bin.pl,v 1.4 2004/07/04 08:44:48 jaalto Exp $

=head1 AUTHOR

Copyright (C) Jari Aalto
This is free software; you can redistribute it and/or modify it under the
same terms as Perl itself or in terms of Gnu General Public licence v2 or
later.

=cut

sub Help (;$)
{
    my $id  = "$LIB.Help";
    my $msg = shift;  # optional arg, why are we here...

    pod2text $PROGRAM_NAME;

    exit 1;
}

# }}}
# {{{ args

# ************************************************************** &amp;args *******
#
#   DESCRIPTION
#
#       Read and interpret command line arguments
#
#   INPUT PARAMETERS
#
#       none
#
#   RETURN VALUES
#
#       none
#
# ****************************************************************************

sub HandleCommandLineArgs ()
{
    my $id = "$LIB.HandleCommandLineArgs";

    my ( $ver, $help );

    # .......................................... command line options ...

    use vars qw
    (
        $FILE

        $debug
        $HELP_OPTION
        $VERSION_OPTION
        $verb

        $OCTAL
        $DECIMAL
        $HEX

        $EXTENSION
        $EVAL_CODE

        $RAW
        $DUMP
        $BEG_COL
        $END_COL
    );

    # .................................................... read args ...

    Getopt::Long::config( qw
    (
        ignore_case
        require_order
    ));

    GetOptions      # Getopt::Long
    (
          "Eval=s"          =&gt; \$EVAL_CODE
        , "beg-column"      =&gt; \$BEG_COL
        , "d"               =&gt; \$debug
        , "debug:i"         =&gt; \$debug
        , "end-column"      =&gt; \$END_COL
        , "e|extension=s"   =&gt; \$EXTENSION
        , "file=s"          =&gt; \$FILE
        , "help"            =&gt; \$help
        , "input-decimal"   =&gt; \$DECIMAL
        , "input-hex"       =&gt; \$HEX
        , "input-octal"     =&gt; \$DECIMAL
        , "raw"             =&gt; \$RAW
        , "verbose"         =&gt; \$verb
        , "Version"         =&gt; \$ver

    );

    $ver        and die "$VERSION $PROGNAME $CONTACT $URL\n";
    $help       and Help();

    $OCTAL      and $DECIMAL=0,     $HEX=0;
    $DECIMAL    and $OCTAL=0,       $HEX=0;
    $HEX        and $OCTAL=0,       $DECIMAL=0;

    unless
    (
           defined $FILE
        or defined $EXTENSION
        or defined $RAW
        or defined $EVAL_CODE
    )
    {
        die "$id: --file --File or --extension option missing";
    }

    if ( defined $EXTENSION )
    {
        local $ARG = $EXTENSION;
        m,/,    and warn "$id: odd Extension request: $EXTENSION\n";
        m,^--,  and warn "$id: odd Extension request: $EXTENSION\n";
    }

    if ( defined $BEG_COL  and  $BEG_COL + 0 &lt; 1)
    {
          die "$id: Must give positive number for --beg-column";
    }

    if ( defined $END_COL  and  $END_COL + 0 &lt; 1)
    {
          die "$id: Must give positive number for --end-column";
    }
}

# }}}
# {{{ Main

# ............................................................ &amp;main ...

sub Main ()
{
    Initialize();
    HandleCommandLineArgs();

    my $id   = "$LIB.main";

    my   $ARGC  = @ARGV;
    push @ARGV, "-" unless @ARGV;                               # pipe

    for my $in ( @ARGV )
    {
        #   If the file is stdin, then write to "tmp.bin", otherwise
        #   derive name from input file.

        my $out = "$in";
        $out    = "outfile"    if  $in eq "-";

        #   However, explicit name overrides all.
        #   BUT the ARGV array must only contain one filename,
        #   otherwise we must derive the name from each file.

        if ( defined $FILE   and   $ARGC == 1)
        {
            # Do nothing, file name already given
        }
        elsif ( defined $EVAL_CODE )
        {
            local $ARG = $out;

            eval  $EVAL_CODE;

            $EVAL_ERROR     and die   "$id: [$EVAL_CODE]  $EVAL_ERROR";
            $debug          and print "$id: [$EVAL_CODE]  $out --&gt; $ARG\n";

            $FILE = $ARG;
        }
        elsif ( defined $EXTENSION )
        {
            $FILE = $out . $EXTENSION;
        }

        # ................................................ write to file ...

        my $OUT = \*STDOUT;

        if ( defined $FILE )
        {
            $FILE eq $in         and die "$id: IN $in and OUT $out are the same." ;

            open STREAM, "&gt; $FILE"  or  die "$id: Can't open [ $FILE ] $ERRNO";
            binmode STREAM;

            $OUT = *STREAM;
        }

        my $stat = open my $IN, "$in";

        unless ( $stat )
        {
            warn "Can't open [$in]";
            next;
        }

        binmode $IN;

        # .................................................... read-file ...

        my $count;

        while ( &lt;$IN&gt; )
        {
            $debug  and print  "READING:&gt;$ARG";

            # .................................................. fixing line ...

            if ( defined $BEG_COL  and   $BEG_COL &gt; 0  and  $END_COL &gt; 0 )
            {
                $ARG = substr $ARG, $BEG_COL, $END_COL;
            }
            elsif ( defined $BEG_COL   and  $BEG_COL &gt; 0  )
            {
                $ARG = substr $ARG, $BEG_COL, length $ARG ;
            }
            elsif (  defined $END_COL  and $END_COL &gt; 0  )
            {
                $ARG = substr $ARG, 0, $END_COL;
            }

            # ............................................... detecting line ...

            #   Must be left flushed number, otherwise skip

            next if ! m,^[0-9a-f][0-9a-f][0-9a-f]+[: ]|^[0-9a-f][0-9a-f]/,i;

            #   NNN: 0a 0b      remove these from the beginning.
            #   NNN  0a 0b

            s/^[0-9]+:\s*//;

            #   00000300  00 00 00 00
            #   The memory address must have at least 3 numbers, otherwise
            #   its "a0" (plain data)

            s/^[0-9a-f][0-9a-f][0-9a-f]+\s*//i;

            #   FF/FF/FF/FF ==&gt; FF FF FF FF

            s,/, ,g;

            #   Remove everything after 3 spaces

            s/ {3}.*//;

            #   Remove anything after item that is not a HEX value
            #
            #   NNN: FF FF FF FF   ................
            #

            s/\s*[^0-9A-Fa-f ].*//;

            #   If this line does not look like hex after cleaning, skip.

            next unless /^[0-9a-f][0-9a-f]/i;

            # ................................................ splitting line ...

            my @fields = split ' ';

            $debug  and print  "\nLOOP:&gt; @fields\n\n";

            for my $i ( @fields )
            {
                #  Either "0a" or "124" octal or "255" decimal,
                #  No other values accepted

                if ( $i =~ /^[0-9A-F][0-9A-F]$|^[0-9][0-9][0-9]?$/i )
                {
                    $count++;

                    print "$i " if $RAW;

                    if ( defined $FILE )
                    {
                        my $val = hex $i;
                        $val = oct $i    if $OCTAL;
                        $val = $i        if $DECIMAL;

                        $out = pack 'C', $val;

                        print $OUT $out;
                    }
                }
            }

            print "\n" if $RAW;
        }

        close IN;

        if ( defined $FILE )
        {
            close OUT;
            print "Wrote $count bytes to $FILE\n";
        }
    }
}

Main();

# }}}

__END__
</pre></body></html>