ISO9660 CD filesystem: Perl parsing library

ISO9660 is standard filesystem used on read-only optical discs (mostly CD-ROM). The standard was based on earlier High Sierra Format (HSF), proposed for CD-ROMs in 1985, and, after several revisions, it was accepted as ISO9960:1998.

The format emphasizes portability (thus having pretty minimal features and very conservative file names standards) and sequential access (which favors disc devices with relatively slow rotation speed).

File extension

iso

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of ISO9660 CD filesystem using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Perl source code to parse ISO9660 CD filesystem

Iso9660.pm

# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

use strict;
use warnings;
use IO::KaitaiStruct 0.007_000;
use Encode;

########################################################################
package Iso9660;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

}

sub sector_size {
    my ($self) = @_;
    return $self->{sector_size} if ($self->{sector_size});
    $self->{sector_size} = 2048;
    return $self->{sector_size};
}

sub primary_vol_desc {
    my ($self) = @_;
    return $self->{primary_vol_desc} if ($self->{primary_vol_desc});
    my $_pos = $self->{_io}->pos();
    $self->{_io}->seek((16 * $self->sector_size()));
    $self->{primary_vol_desc} = Iso9660::VolDesc->new($self->{_io}, $self, $self->{_root});
    $self->{_io}->seek($_pos);
    return $self->{primary_vol_desc};
}

########################################################################
package Iso9660::VolDescPrimary;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{unused1} = $self->{_io}->ensure_fixed_contents(pack('C*', (0)));
    $self->{system_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(32));
    $self->{volume_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(32));
    $self->{unused2} = $self->{_io}->ensure_fixed_contents(pack('C*', (0, 0, 0, 0, 0, 0, 0, 0)));
    $self->{vol_space_size} = Iso9660::U4bi->new($self->{_io}, $self, $self->{_root});
    $self->{unused3} = $self->{_io}->ensure_fixed_contents(pack('C*', (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
    $self->{vol_set_size} = Iso9660::U2bi->new($self->{_io}, $self, $self->{_root});
    $self->{vol_seq_num} = Iso9660::U2bi->new($self->{_io}, $self, $self->{_root});
    $self->{logical_block_size} = Iso9660::U2bi->new($self->{_io}, $self, $self->{_root});
    $self->{path_table_size} = Iso9660::U4bi->new($self->{_io}, $self, $self->{_root});
    $self->{lba_path_table_le} = $self->{_io}->read_u4le();
    $self->{lba_opt_path_table_le} = $self->{_io}->read_u4le();
    $self->{lba_path_table_be} = $self->{_io}->read_u4be();
    $self->{lba_opt_path_table_be} = $self->{_io}->read_u4be();
    $self->{_raw_root_dir} = $self->{_io}->read_bytes(34);
    my $io__raw_root_dir = IO::KaitaiStruct::Stream->new($self->{_raw_root_dir});
    $self->{root_dir} = Iso9660::DirEntry->new($io__raw_root_dir, $self, $self->{_root});
    $self->{vol_set_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(128));
    $self->{publisher_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(128));
    $self->{data_preparer_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(128));
    $self->{application_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(128));
    $self->{copyright_file_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(38));
    $self->{abstract_file_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(36));
    $self->{bibliographic_file_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(37));
    $self->{vol_create_datetime} = Iso9660::DecDatetime->new($self->{_io}, $self, $self->{_root});
    $self->{vol_mod_datetime} = Iso9660::DecDatetime->new($self->{_io}, $self, $self->{_root});
    $self->{vol_expire_datetime} = Iso9660::DecDatetime->new($self->{_io}, $self, $self->{_root});
    $self->{vol_effective_datetime} = Iso9660::DecDatetime->new($self->{_io}, $self, $self->{_root});
    $self->{file_structure_version} = $self->{_io}->read_u1();
    $self->{unused4} = $self->{_io}->read_u1();
    $self->{application_area} = $self->{_io}->read_bytes(512);
}

sub path_table {
    my ($self) = @_;
    return $self->{path_table} if ($self->{path_table});
    my $_pos = $self->{_io}->pos();
    $self->{_io}->seek(($self->lba_path_table_le() * $self->_root()->sector_size()));
    $self->{_raw_path_table} = $self->{_io}->read_bytes($self->path_table_size()->le());
    my $io__raw_path_table = IO::KaitaiStruct::Stream->new($self->{_raw_path_table});
    $self->{path_table} = Iso9660::PathTableLe->new($io__raw_path_table, $self, $self->{_root});
    $self->{_io}->seek($_pos);
    return $self->{path_table};
}

sub unused1 {
    my ($self) = @_;
    return $self->{unused1};
}

sub system_id {
    my ($self) = @_;
    return $self->{system_id};
}

sub volume_id {
    my ($self) = @_;
    return $self->{volume_id};
}

sub unused2 {
    my ($self) = @_;
    return $self->{unused2};
}

sub vol_space_size {
    my ($self) = @_;
    return $self->{vol_space_size};
}

sub unused3 {
    my ($self) = @_;
    return $self->{unused3};
}

sub vol_set_size {
    my ($self) = @_;
    return $self->{vol_set_size};
}

sub vol_seq_num {
    my ($self) = @_;
    return $self->{vol_seq_num};
}

sub logical_block_size {
    my ($self) = @_;
    return $self->{logical_block_size};
}

sub path_table_size {
    my ($self) = @_;
    return $self->{path_table_size};
}

sub lba_path_table_le {
    my ($self) = @_;
    return $self->{lba_path_table_le};
}

sub lba_opt_path_table_le {
    my ($self) = @_;
    return $self->{lba_opt_path_table_le};
}

sub lba_path_table_be {
    my ($self) = @_;
    return $self->{lba_path_table_be};
}

sub lba_opt_path_table_be {
    my ($self) = @_;
    return $self->{lba_opt_path_table_be};
}

sub root_dir {
    my ($self) = @_;
    return $self->{root_dir};
}

sub vol_set_id {
    my ($self) = @_;
    return $self->{vol_set_id};
}

sub publisher_id {
    my ($self) = @_;
    return $self->{publisher_id};
}

sub data_preparer_id {
    my ($self) = @_;
    return $self->{data_preparer_id};
}

sub application_id {
    my ($self) = @_;
    return $self->{application_id};
}

sub copyright_file_id {
    my ($self) = @_;
    return $self->{copyright_file_id};
}

sub abstract_file_id {
    my ($self) = @_;
    return $self->{abstract_file_id};
}

sub bibliographic_file_id {
    my ($self) = @_;
    return $self->{bibliographic_file_id};
}

sub vol_create_datetime {
    my ($self) = @_;
    return $self->{vol_create_datetime};
}

sub vol_mod_datetime {
    my ($self) = @_;
    return $self->{vol_mod_datetime};
}

sub vol_expire_datetime {
    my ($self) = @_;
    return $self->{vol_expire_datetime};
}

sub vol_effective_datetime {
    my ($self) = @_;
    return $self->{vol_effective_datetime};
}

sub file_structure_version {
    my ($self) = @_;
    return $self->{file_structure_version};
}

sub unused4 {
    my ($self) = @_;
    return $self->{unused4};
}

sub application_area {
    my ($self) = @_;
    return $self->{application_area};
}

sub _raw_root_dir {
    my ($self) = @_;
    return $self->{_raw_root_dir};
}

sub _raw_path_table {
    my ($self) = @_;
    return $self->{_raw_path_table};
}

########################################################################
package Iso9660::VolDescBootRecord;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{boot_system_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(32));
    $self->{boot_id} = Encode::decode("UTF-8", $self->{_io}->read_bytes(32));
}

sub boot_system_id {
    my ($self) = @_;
    return $self->{boot_system_id};
}

sub boot_id {
    my ($self) = @_;
    return $self->{boot_id};
}

########################################################################
package Iso9660::Datetime;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{year} = $self->{_io}->read_u1();
    $self->{month} = $self->{_io}->read_u1();
    $self->{day} = $self->{_io}->read_u1();
    $self->{hour} = $self->{_io}->read_u1();
    $self->{minute} = $self->{_io}->read_u1();
    $self->{sec} = $self->{_io}->read_u1();
    $self->{timezone} = $self->{_io}->read_u1();
}

sub year {
    my ($self) = @_;
    return $self->{year};
}

sub month {
    my ($self) = @_;
    return $self->{month};
}

sub day {
    my ($self) = @_;
    return $self->{day};
}

sub hour {
    my ($self) = @_;
    return $self->{hour};
}

sub minute {
    my ($self) = @_;
    return $self->{minute};
}

sub sec {
    my ($self) = @_;
    return $self->{sec};
}

sub timezone {
    my ($self) = @_;
    return $self->{timezone};
}

########################################################################
package Iso9660::DirEntry;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{len} = $self->{_io}->read_u1();
    if ($self->len() > 0) {
        $self->{_raw_body} = $self->{_io}->read_bytes(($self->len() - 1));
        my $io__raw_body = IO::KaitaiStruct::Stream->new($self->{_raw_body});
        $self->{body} = Iso9660::DirEntryBody->new($io__raw_body, $self, $self->{_root});
    }
}

sub len {
    my ($self) = @_;
    return $self->{len};
}

sub body {
    my ($self) = @_;
    return $self->{body};
}

sub _raw_body {
    my ($self) = @_;
    return $self->{_raw_body};
}

########################################################################
package Iso9660::VolDesc;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{type} = $self->{_io}->read_u1();
    $self->{magic} = $self->{_io}->ensure_fixed_contents(pack('C*', (67, 68, 48, 48, 49)));
    $self->{version} = $self->{_io}->read_u1();
    if ($self->type() == 0) {
        $self->{vol_desc_boot_record} = Iso9660::VolDescBootRecord->new($self->{_io}, $self, $self->{_root});
    }
    if ($self->type() == 1) {
        $self->{vol_desc_primary} = Iso9660::VolDescPrimary->new($self->{_io}, $self, $self->{_root});
    }
}

sub type {
    my ($self) = @_;
    return $self->{type};
}

sub magic {
    my ($self) = @_;
    return $self->{magic};
}

sub version {
    my ($self) = @_;
    return $self->{version};
}

sub vol_desc_boot_record {
    my ($self) = @_;
    return $self->{vol_desc_boot_record};
}

sub vol_desc_primary {
    my ($self) = @_;
    return $self->{vol_desc_primary};
}

########################################################################
package Iso9660::PathTableEntryLe;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{len_dir_name} = $self->{_io}->read_u1();
    $self->{len_ext_attr_rec} = $self->{_io}->read_u1();
    $self->{lba_extent} = $self->{_io}->read_u4le();
    $self->{parent_dir_idx} = $self->{_io}->read_u2le();
    $self->{dir_name} = Encode::decode("UTF-8", $self->{_io}->read_bytes($self->len_dir_name()));
    if (($self->len_dir_name() % 2) == 1) {
        $self->{padding} = $self->{_io}->read_u1();
    }
}

sub len_dir_name {
    my ($self) = @_;
    return $self->{len_dir_name};
}

sub len_ext_attr_rec {
    my ($self) = @_;
    return $self->{len_ext_attr_rec};
}

sub lba_extent {
    my ($self) = @_;
    return $self->{lba_extent};
}

sub parent_dir_idx {
    my ($self) = @_;
    return $self->{parent_dir_idx};
}

sub dir_name {
    my ($self) = @_;
    return $self->{dir_name};
}

sub padding {
    my ($self) = @_;
    return $self->{padding};
}

########################################################################
package Iso9660::DirEntries;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{entries} = ();
    do {
        $_ = Iso9660::DirEntry->new($self->{_io}, $self, $self->{_root});
        push @{$self->{entries}}, $_;
    } until ($_->len() == 0);
}

sub entries {
    my ($self) = @_;
    return $self->{entries};
}

########################################################################
package Iso9660::U4bi;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{le} = $self->{_io}->read_u4le();
    $self->{be} = $self->{_io}->read_u4be();
}

sub le {
    my ($self) = @_;
    return $self->{le};
}

sub be {
    my ($self) = @_;
    return $self->{be};
}

########################################################################
package Iso9660::U2bi;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{le} = $self->{_io}->read_u2le();
    $self->{be} = $self->{_io}->read_u2be();
}

sub le {
    my ($self) = @_;
    return $self->{le};
}

sub be {
    my ($self) = @_;
    return $self->{be};
}

########################################################################
package Iso9660::PathTableLe;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{entries} = ();
    while (!$self->{_io}->is_eof()) {
        push @{$self->{entries}}, Iso9660::PathTableEntryLe->new($self->{_io}, $self, $self->{_root});
    }
}

sub entries {
    my ($self) = @_;
    return $self->{entries};
}

########################################################################
package Iso9660::DecDatetime;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{year} = Encode::decode("ASCII", $self->{_io}->read_bytes(4));
    $self->{month} = Encode::decode("ASCII", $self->{_io}->read_bytes(2));
    $self->{day} = Encode::decode("ASCII", $self->{_io}->read_bytes(2));
    $self->{hour} = Encode::decode("ASCII", $self->{_io}->read_bytes(2));
    $self->{minute} = Encode::decode("ASCII", $self->{_io}->read_bytes(2));
    $self->{sec} = Encode::decode("ASCII", $self->{_io}->read_bytes(2));
    $self->{sec_hundreds} = Encode::decode("ASCII", $self->{_io}->read_bytes(2));
    $self->{timezone} = $self->{_io}->read_u1();
}

sub year {
    my ($self) = @_;
    return $self->{year};
}

sub month {
    my ($self) = @_;
    return $self->{month};
}

sub day {
    my ($self) = @_;
    return $self->{day};
}

sub hour {
    my ($self) = @_;
    return $self->{hour};
}

sub minute {
    my ($self) = @_;
    return $self->{minute};
}

sub sec {
    my ($self) = @_;
    return $self->{sec};
}

sub sec_hundreds {
    my ($self) = @_;
    return $self->{sec_hundreds};
}

sub timezone {
    my ($self) = @_;
    return $self->{timezone};
}

########################################################################
package Iso9660::DirEntryBody;

our @ISA = 'IO::KaitaiStruct::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, IO::KaitaiStruct::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = IO::KaitaiStruct::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;;

    $self->_read();

    return $self;
}

sub _read {
    my ($self) = @_;

    $self->{len_ext_attr_rec} = $self->{_io}->read_u1();
    $self->{lba_extent} = Iso9660::U4bi->new($self->{_io}, $self, $self->{_root});
    $self->{size_extent} = Iso9660::U4bi->new($self->{_io}, $self, $self->{_root});
    $self->{datetime} = Iso9660::Datetime->new($self->{_io}, $self, $self->{_root});
    $self->{file_flags} = $self->{_io}->read_u1();
    $self->{file_unit_size} = $self->{_io}->read_u1();
    $self->{interleave_gap_size} = $self->{_io}->read_u1();
    $self->{vol_seq_num} = Iso9660::U2bi->new($self->{_io}, $self, $self->{_root});
    $self->{len_file_name} = $self->{_io}->read_u1();
    $self->{file_name} = Encode::decode("UTF-8", $self->{_io}->read_bytes($self->len_file_name()));
    if (($self->len_file_name() % 2) == 0) {
        $self->{padding} = $self->{_io}->read_u1();
    }
    $self->{rest} = $self->{_io}->read_bytes_full();
}

sub extent_as_dir {
    my ($self) = @_;
    return $self->{extent_as_dir} if ($self->{extent_as_dir});
    if (($self->file_flags() & 2) != 0) {
        my $io = $self->_root()->_io();
        my $_pos = $io->pos();
        $io->seek(($self->lba_extent()->le() * $self->_root()->sector_size()));
        $self->{_raw_extent_as_dir} = $io->read_bytes($self->size_extent()->le());
        my $io__raw_extent_as_dir = IO::KaitaiStruct::Stream->new($self->{_raw_extent_as_dir});
        $self->{extent_as_dir} = Iso9660::DirEntries->new($io__raw_extent_as_dir, $self, $self->{_root});
        $io->seek($_pos);
    }
    return $self->{extent_as_dir};
}

sub extent_as_file {
    my ($self) = @_;
    return $self->{extent_as_file} if ($self->{extent_as_file});
    if (($self->file_flags() & 2) == 0) {
        my $io = $self->_root()->_io();
        my $_pos = $io->pos();
        $io->seek(($self->lba_extent()->le() * $self->_root()->sector_size()));
        $self->{extent_as_file} = $io->read_bytes($self->size_extent()->le());
        $io->seek($_pos);
    }
    return $self->{extent_as_file};
}

sub len_ext_attr_rec {
    my ($self) = @_;
    return $self->{len_ext_attr_rec};
}

sub lba_extent {
    my ($self) = @_;
    return $self->{lba_extent};
}

sub size_extent {
    my ($self) = @_;
    return $self->{size_extent};
}

sub datetime {
    my ($self) = @_;
    return $self->{datetime};
}

sub file_flags {
    my ($self) = @_;
    return $self->{file_flags};
}

sub file_unit_size {
    my ($self) = @_;
    return $self->{file_unit_size};
}

sub interleave_gap_size {
    my ($self) = @_;
    return $self->{interleave_gap_size};
}

sub vol_seq_num {
    my ($self) = @_;
    return $self->{vol_seq_num};
}

sub len_file_name {
    my ($self) = @_;
    return $self->{len_file_name};
}

sub file_name {
    my ($self) = @_;
    return $self->{file_name};
}

sub padding {
    my ($self) = @_;
    return $self->{padding};
}

sub rest {
    my ($self) = @_;
    return $self->{rest};
}

sub _raw_extent_as_dir {
    my ($self) = @_;
    return $self->{_raw_extent_as_dir};
}

1;