#!/usr/bin/env perl use strict ; use warnings ; use Carp ; =head1 NAME $>hdr - hexadecimal [decimal] ascii, colorizing, range dump =head1 USAGE $> hdr -r range_definitions file_to_dump $> hdr file_to_dump -r 'cookie,10,yellow :padding,8 :size,4:data,100' -o ver The integer part can of a range definition and offset values can be hexadecimal value starting with I<0x> =head1 RANGE DEFINITION format range example normal range => integer header, 4, bright_blue comment => # data section start, # extra header => @ header, @, red bitfield => [XInteger][xInteger]bInteger bitfield, X2x4b4 (offset: X byte, x bit) skip range => XInteger boring, X256,, your comment =head1 OPTIONS Options can be given before or after the name of the file to dump. range_description|r file name containing a description or a string description formated as: 'name,size,color:name,size:name,size:...' dump_original_range_description dump the un-processed range descriptions dump_range_description dump the processed range descriptions offset position in the data where to start dumping offset_start value added to the offset before display maximum_size amount of data to dump orientation|o 'horizontal' or 'vertical' display_column_names|col display columns names display_ruler|rul display horizontal ruler format|f 'ANSI' or 'ASCII' or 'HTML' display_command_line make the command line part of the output color 'cycle', 'no_cycle', or 'bw' colors file containing custom colors start_color name of the first random color to use start_tag/end_tag text that is output before and after the dump see L<hdr_examples.pod> data_width|w number of bytes per dump line offset_format 'hex' or 'dec' display_offset 0 == no the offset display display_cumulative_offset 0 == no cumulative offset display display_zero_size_range 0 == no display of range with size 0 display_zero_size_range_warning 0 == no warnings about ranges with size 0 display_comment_range 0 == no comment range display display_range_name 1 == display of the range name maximum_range_name_size truncate range name if longer display_range_size 1 == prepend the range size to the name display_hex_dump 1 == display hexadecimal dump column display_hexascii_dump 1 == display vombined HEX and ASCII dump column display_dec_dump 1 == display decimal dump column display_ascii_dump 1 == display ASCII dump column display_user_information 1 == display user information columns maximum_user_information_size truncate user information if longer display_bitfields 1 == display bitfields display_source 1 == display source for bitfields maximum_bitfield_source_size truncate bitfield source name if longer bit_zero_on_left 1 == bit index zero is on the left h|help display this scripts help page generate_completion_script|bash generates a completion script on STDOUT =head1 EXAMPLES See L<hdr_examples.pod> in the distribution. =head1 EXIT STATUS Non zero if an error occured. =head1 AUTHOR Nadim ibn hamouda el Khemir CPAN ID: NKH mailto: nkh@cpan.org =cut #------------------------------------------------------------------------------------------------------------------------ use Getopt::Long ; use English qw( -no_match_vars ) ; use File::Slurp ; use IO::Select ; use Data::HexDump::Range qw() ; use Term::Bash::Completion::Generator ; our $VERSION = '0.05' ; use Readonly ; Readonly my $SIZE_IF_RANGE_ERROR=> 256 ; Readonly my $DEFAULT_SIZE => 16 ; Readonly my $DEFAULT_USER_INFORMATION_SIZE => 20 ; Readonly my $DEFAULT_BITFIELD_SOURCE_SIZE => 8 ; #------------------------------------------------------------------------------------------------------------------------ my @options = ( 'range_description|r=s' => \ my $range_description, 'dump_range_description|d' =>\my $dump_range_description, 'dump_original_range_description' =>\my $dump_original_range_description, 'offset=o' => \my $offset, 'offset_start=o' => \my $offset_start, 'maximum_size=o' => \my $maximum_size, 'orientation|o=s' => \my $orientation, 'display_column_names|col' => \my $display_column_names, 'display_ruler|rul' => \my $display_ruler, 'format|f=s' => \my $format, 'display_command_line' => \my $display_command_line, 'color=s' => \my $color, 'colors=s' => \my $color_file, 'start_color=s' => \my $start_color, 'start_tag=s' => \my $start_tag, 'end_tag=s' => \my $end_tag, 'data_width=o' => \my $data_width, 'offset_format=s' => \my $offset_format, 'display_offset=i' => \my $display_offset, 'display_cumulative_offset=i' => \my $display_cumulative_offset, 'display_zero_size_range=i' => \my $display_zero_size_range, 'display_comment_range=i' => \my $display_comment_range, 'display_zero_size_range_warning=i' => \my $display_zero_size_range_warning, 'display_range_name=i' => \my $display_range_name, 'maximum_range_name_size=i' => \my$maximum_range_name_size, 'display_range_size=i' => \my $display_range_size, 'display_hex_dump=i' => \my $display_hex_dump, 'display_hexascii_dump=i' => \my $display_hexascii_dump, 'display_dec_dump=i' => \my $display_dec_dump, 'display_ascii_dump=i' => \my $display_ascii_dump, 'display_user_information=i' => \my $display_user_information, 'maximum_user_information_size=i' => \my $maximum_user_information_size, 'display_bitfields=i' => \my $display_bitfields, 'display_bitfield_source=i' => \my $display_bitfield_source, 'maximum_bitfield_source_size=i' => \my $maximum_bitfield_source_size, 'bit_zero_on_left' => \my $bit_zero_on_left, 'h|help' => \&display_help, 'generate_completion_script|bash' => \my $generatebash_completion, ) ; my @ARGV_COPY = @ARGV ; # getopt removes elements display_help() unless GetOptions(@options) ; generate_completion_script(@options) if $generatebash_completion ; print "\n$start_tag\n\n" if defined $start_tag ; if($display_command_line) { use Text::Colorizer ; my $c= Text::Colorizer->new(FORMAT => $format || 'ANSI', JOIN => q{ }) ; print $c->color_all('bright_white', 'hdr', grep{! /-output_command_line/xsm} @ARGV_COPY) ; } my $data ; my $io_select = IO::Select->new(\*STDIN) ; if($io_select->can_read(0)) { local $INPUT_RECORD_SEPARATOR = undef ; $data = <STDIN> ; ## no critic (InputOutput::ProhibitExplicitStdin) } else { my $file_to_dump = shift @ARGV ; if(defined $file_to_dump) { $data = read_file $file_to_dump; } else { croak "Error: You didn't give me anything to generate an hexdump from. Try the --help option.\n"; } } $offset ||= 0 ; my $range ; if(defined $range_description ) { if($range_description =~ /,/xsm) { $range = $range_description ; } else { # a file #~ $range = do $range_description || ["hdr: range error $@", $SIZE_IF_RANGE_ERROR ] ; unless ($range = do $range_description ) { if($@) { carp "ERROR: Couldn't parse $range_description:\n\t$@"; } elsif(! defined $range) { carp "ERROR: Couldn't do $range_description:\n\t$!" } $range = ["hdr: range error", $SIZE_IF_RANGE_ERROR ] ; } } } else { $range = ['no range definition', length($data) ] ; $display_range_name = 0 ; $display_bitfield_source = 0 ; } my @color_file ; @color_file = (COLOR_NAMES => $color_file) if(defined $color_file) ; my $hdr = Data::HexDump::Range->new ( INTERACTION => {WARN => sub {warn @_}}, ## no critic (ErrorHandling::RequireCarping) ORIENTATION => $orientation || 'horizontal', DISPLAY_COLUMN_NAMES => defined $display_column_names ? $display_column_names : 0, DISPLAY_RULER => defined $display_ruler ? $display_ruler : 0, FORMAT => $format || 'ANSI', COLOR => defined $color ? $color : 'cycle', START_COLOR => $start_color, OFFSET_FORMAT => $offset_format || 'hex', OFFSET_START => $offset_start || 0, DATA_WIDTH => $data_width || $DEFAULT_SIZE, DISPLAY_RANGE_NAME => defined $display_range_name ? $display_range_name : 1 , DUMP_RANGE_DESCRIPTION => defined $dump_range_description ? $dump_range_description : 0 , DUMP_ORIGINAL_RANGE_DESCRIPTION => defined $dump_original_range_description ? $dump_original_range_description : 0 , MAXIMUM_RANGE_NAME_SIZE => defined $maximum_range_name_size ? $maximum_range_name_size : $DEFAULT_SIZE, DISPLAY_RANGE_SIZE => defined $display_range_size ? $display_range_size : 0, DISPLAY_OFFSET => defined $display_offset ? $display_offset : 1 , DISPLAY_CUMULATIVE_OFFSET => defined $display_cumulative_offset ? $display_cumulative_offset : 1 , DISPLAY_HEX_DUMP => defined $display_hex_dump ? $display_hex_dump : 1, DISPLAY_HEXASCII_DUMP => defined $display_hexascii_dump ? $display_hexascii_dump : 0, DISPLAY_DEC_DUMP => defined $display_dec_dump ? $display_dec_dump : 0, DISPLAY_ASCII_DUMP => defined $display_ascii_dump ? $display_ascii_dump : 1 , DISPLAY_USER_INFORMATION => defined $display_user_information ? $display_user_information : 0 , MAXIMUM_USER_INFORMATION_SIZE => defined $maximum_user_information_size ? $maximum_user_information_size : $DEFAULT_USER_INFORMATION_SIZE, DISPLAY_ZERO_SIZE_RANGE => defined $display_zero_size_range ? $display_zero_size_range : 1, DISPLAY_ZERO_SIZE_RANGE_WARNING => defined $display_zero_size_range_warning ? $display_zero_size_range_warning : 1, DISPLAY_COMMENT_RANGE => defined $display_comment_range ? $display_comment_range : 1, DISPLAY_BITFIELDS => $display_bitfields, DISPLAY_BITFIELD_SOURCE => defined $display_bitfield_source ? $display_bitfield_source : 1, MAXIMUM_BITFIELD_SOURCE_SIZE => defined $maximum_bitfield_source_size ? $maximum_bitfield_source_size: $DEFAULT_BITFIELD_SOURCE_SIZE, BIT_ZERO_ON_LEFT => defined $bit_zero_on_left ? $bit_zero_on_left : 0, @color_file ) ; print $hdr->dump( $range, $data, $offset, $maximum_size) ; print "\n$end_tag\n\n" if defined $end_tag ; #------------------------------------------------------------------------------------------------------------------------ sub display_help { #~ =head2 display_help() #~ I<Arguments> - None #~ I<Returns> - Nothing #~ I<Exceptions> - exits with status code B<1> #~ =cut my ($this_script) = ($PROGRAM_NAME =~m/(.*)/sxm ) ; print {*STDERR} `perldoc $this_script` or croak 'Error: Can\'t display help!' ; ## no critic (InputOutput::ProhibitBacktickOperators) exit(1) ; } #------------------------------------------------------------------------------------------------------------------------ sub generate_completion_script { #~ =head2 generate_completion_script(@definitions) #~ I<Arguments> - @definitions - getop options description #~ I<Returns> - Nothing #~ I<Exceptions> - exits with status code B<1> after emitting the completion script on stdout #~ =cut my (@definitions) = @_ ; my $flip = 0 ; my @options = grep {++$flip % 2} @definitions ; print Term::Bash::Completion::Generator::generate_bash_completion_function('hdr', [@options], undef, 1) ; exit(0) ; }