Jason W.
Jason W.

Reputation: 163

Parsing a binary file in Perl and returning a value at a specified offset

I have a binary file that I need to be able to parse through. I'm looking to specify an offset and then have the program return the byte value at that location.

I'm not sure about how to go about this. I've got the file open part, but I don't know how to get the program to jump to the location.

Upvotes: 2

Views: 3925

Answers (2)

Greg Bacon
Greg Bacon

Reputation: 139711

Use seek and the handy constants from the Fcntl module as in

#! /usr/bin/env perl

use bytes;
use strict;
use warnings;

use Fcntl ':seek';

open my $fh, "<", $0 or die "$0: open: $!";

seek $fh, 0, SEEK_END or die "$0: seek: $!";

my $last = tell $fh;
die "$0: tell: $!" if $last < 0;

for (1 .. 20) {
    my $offset = int rand($last + 1);
    seek $fh, $offset, SEEK_SET or die "$0: seek: $!";
    defined read $fh, my $byte, 1 or die "$0: read: $!";
    $byte = "\\$byte" if $byte eq "'" || $byte eq "\\";
    printf "offset %*d: \\x%02x%s\n",
      length $last, $offset,
      unpack("C", $byte),
      $byte =~ /[[:print:]]/a ? " '$byte'" : "";
}
__DATA__
🐫 𝕲𝖔  π•Ώπ–π–”π–š  𝖆𝖓𝖉  𝕯𝖔  π•·π–Žπ–π–Šπ–œπ–Žπ–˜π–Š 🐫
𝓔𝓭𝓲𝓽 :  π™Žπ™žπ™’π™₯π™‘π™šπ™¨π™© β„ž:   πŸ• π˜Ώπ™žπ™¨π™˜π™§π™šπ™©π™š  π™π™šπ™˜π™€π™’π™’π™šπ™£π™™π™–π™©π™žπ™€π™£π™¨
πŸŽ…      𝕹 𝖔   𝕸 𝖆 π–Œ π–Ž π–ˆ   𝕭 π–š 𝖑 𝖑 π–Š 𝖙    πŸŽ…
πŸ’©          𝔸 𝕀 𝕀 𝕦 π•ž 𝕖   𝔹 𝕣 𝕠 π•œ 𝕖 π•Ÿ π•Ÿ 𝕖 𝕀 𝕀           πŸ’©
😈 Β‘Ζ¨dlΙ™Ι₯ ƨᴉΙ₯Κ‡ Ι™doΙ₯ puɐ ʻλɐp əɔᴉu ɐ Ι™ΚŒΙΙ₯ Κ»ΚžΙ”nl poo⅁ 😈

Sample output:

offset   47: \x65 'e'
offset  392: \x20 ' '
offset  704: \xf0
offset  427: \x5c '\''
offset  524: \x61 'a'
offset 1088: \x75 'u'
offset  413: \x20 ' '
offset 1093: \xbb
offset 1112: \xc9
offset  377: \x24 '$'
offset   64: \x46 'F'
offset  361: \x62 'b'
offset  898: \xf0
offset  566: \x5d ']'
offset  843: \xf0
offset 1075: \xc9
offset  280: \x20 ' '
offset    3: \x2f '/'
offset  673: \x8a
offset  153: \x20 ' '

The contents of the __DATA__ section were borrowed from Tom’s excellent suggestions for dealing with UTF-8 in Perl programs.

Upvotes: 2

tchrist
tchrist

Reputation: 80443

use Fcntl qw(:seek);

my($fh, $filename, $byte_position, $byte_value);

$filename      = "/some/file/name/goes/here";
$byte_position = 42;

open($fh, "<", $filename)
  || die "can't open $filename: $!";

binmode($fh)
  || die "can't binmode $filename";

sysseek($fh, $byte_position, SEEK_CUR)  # NB: 0-based
  || die "couldn't see to byte $byte_position in $filename: $!";

sysread($fh, $byte_value, 1) == 1
  || die "couldn't read byte from $filename: $!";

printf "read byte with ordinal value %#02x at position %d\n",
     ord($byte_value), $byte_position;

Upvotes: 5

Related Questions