package Compress::Raw::Lzma; use strict ; use warnings ; require 5.006 ; require Exporter; use AutoLoader; use Carp ; use bytes ; our ($VERSION, $XS_VERSION, @ISA, @EXPORT, $AUTOLOAD); $VERSION = '2.221'; $XS_VERSION = $VERSION; $VERSION = eval $VERSION; @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. @EXPORT = qw( LZMA_OK LZMA_STREAM_END LZMA_NO_CHECK LZMA_UNSUPPORTED_CHECK LZMA_GET_CHECK LZMA_MEM_ERROR LZMA_MEMLIMIT_ERROR LZMA_FORMAT_ERROR LZMA_OPTIONS_ERROR LZMA_DATA_ERROR LZMA_BUF_ERROR LZMA_PROG_ERROR LZMA_RUN LZMA_SYNC_FLUSH LZMA_FULL_FLUSH LZMA_FINISH LZMA_FILTER_X86 LZMA_FILTER_POWERPC LZMA_FILTER_IA64 LZMA_FILTER_ARM LZMA_FILTER_ARMTHUMB LZMA_FILTER_SPARC LZMA_BLOCK_HEADER_SIZE_MIN LZMA_BLOCK_HEADER_SIZE_MAX LZMA_CHECK_NONE LZMA_CHECK_CRC32 LZMA_CHECK_CRC64 LZMA_CHECK_SHA256 LZMA_CHECK_ID_MAX LZMA_CHECK_SIZE_MAX LZMA_PRESET_DEFAULT LZMA_PRESET_LEVEL_MASK LZMA_PRESET_EXTREME LZMA_TELL_NO_CHECK LZMA_TELL_UNSUPPORTED_CHECK LZMA_TELL_ANY_CHECK LZMA_CONCATENATED LZMA_FILTER_DELTA LZMA_DELTA_DIST_MIN LZMA_DELTA_DIST_MAX LZMA_DELTA_TYPE_BYTE LZMA_FILTERS_MAX LZMA_FILTER_LZMA2 LZMA_MF_HC3 LZMA_MF_HC4 LZMA_MF_BT2 LZMA_MF_BT3 LZMA_MF_BT4 LZMA_MODE_FAST LZMA_MODE_NORMAL LZMA_DICT_SIZE_MIN LZMA_DICT_SIZE_DEFAULT LZMA_LCLP_MIN LZMA_LCLP_MAX LZMA_LC_DEFAULT LZMA_LP_DEFAULT LZMA_PB_MIN LZMA_PB_MAX LZMA_PB_DEFAULT LZMA_STREAM_HEADER_SIZE LZMA_BACKWARD_SIZE_MIN LZMA_VERSION LZMA_VERSION_MAJOR LZMA_VERSION_MINOR LZMA_VERSION_PATCH LZMA_VERSION_STABILITY LZMA_VERSION_STABILITY_STRING LZMA_VERSION_STRING ); #LZMA_VLI_MAX #LZMA_VLI_UNKNOWN #LZMA_VLI_BYTES_MAX sub AUTOLOAD { my($constname); ($constname = $AUTOLOAD) =~ s/.*:://; my ($error, $val) = constant($constname); Carp::croak $error if $error; no strict 'refs'; *{$AUTOLOAD} = sub { $val }; goto &{$AUTOLOAD}; } use constant FLAG_APPEND => 1 ; use constant FLAG_CRC => 2 ; use constant FLAG_ADLER => 4 ; use constant FLAG_CONSUME_INPUT => 8 ; use constant FLAG_LIMIT_OUTPUT => 16 ; eval { require XSLoader; XSLoader::load('Compress::Raw::Lzma', $XS_VERSION); 1; } or do { require DynaLoader; local @ISA = qw(DynaLoader); bootstrap Compress::Raw::Lzma $XS_VERSION ; }; use constant Parse_any => 0x01; use constant Parse_unsigned => 0x02; use constant Parse_signed => 0x04; use constant Parse_boolean => 0x08; use constant Parse_string => 0x10; use constant Parse_custom => 0x12; use constant Parse_store_ref => 0x100 ; use constant OFF_PARSED => 0 ; use constant OFF_TYPE => 1 ; use constant OFF_DEFAULT => 2 ; use constant OFF_FIXED => 3 ; use constant OFF_FIRST_ONLY => 4 ; use constant OFF_STICKY => 5 ; sub ParseParameters { my $level = shift || 0 ; my $sub = (caller($level + 1))[3] ; #local $Carp::CarpLevel = 1 ; my $p = new Compress::Raw::Lzma::Parameters() ; $p->parse(@_) or croak "$sub: $p->{Error}" ; return $p; } sub Compress::Raw::Lzma::Parameters::new { my $class = shift ; my $obj = { Error => '', Got => {}, } ; #return bless $obj, ref($class) || $class || __PACKAGE__ ; return bless $obj, 'Compress::Raw::Lzma::Parameters' ; } sub Compress::Raw::Lzma::Parameters::setError { my $self = shift ; my $error = shift ; my $retval = @_ ? shift : undef ; $self->{Error} = $error ; return $retval; } #sub getError #{ # my $self = shift ; # return $self->{Error} ; #} sub Compress::Raw::Lzma::Parameters::parse { my $self = shift ; my $default = shift ; my $got = $self->{Got} ; my $firstTime = keys %{ $got } == 0 ; my (@Bad) ; my @entered = () ; # Allow the options to be passed as a hash reference or # as the complete hash. if (@_ == 0) { @entered = () ; } elsif (@_ == 1) { my $href = $_[0] ; return $self->setError("Expected even number of parameters, got 1") if ! defined $href or ! ref $href or ref $href ne "HASH" ; foreach my $key (keys %$href) { push @entered, $key ; push @entered, \$href->{$key} ; } } else { my $count = @_; return $self->setError("Expected even number of parameters, got $count") if $count % 2 != 0 ; for my $i (0.. $count / 2 - 1) { push @entered, $_[2* $i] ; push @entered, \$_[2* $i+1] ; } } while (my ($key, $v) = each %$default) { croak "need 4 params [@$v]" if @$v != 4 ; my ($first_only, $sticky, $type, $value) = @$v ; my $x ; $self->_checkType($key, \$value, $type, 0, \$x) or return undef ; $key = lc $key; if ($firstTime || ! $sticky) { $got->{$key} = [0, $type, $value, $x, $first_only, $sticky] ; } $got->{$key}[OFF_PARSED] = 0 ; } for my $i (0.. @entered / 2 - 1) { my $key = $entered[2* $i] ; my $value = $entered[2* $i+1] ; #print "Key [$key] Value [$value]" ; #print defined $$value ? "[$$value]\n" : "[undef]\n"; $key =~ s/^-// ; my $canonkey = lc $key; if ($got->{$canonkey} && ($firstTime || ! $got->{$canonkey}[OFF_FIRST_ONLY] )) { my $type = $got->{$canonkey}[OFF_TYPE] ; my $s ; $self->_checkType($key, $value, $type, 1, \$s) or return undef ; #$value = $$value unless $type & Parse_store_ref ; $value = $$value ; $got->{$canonkey} = [1, $type, $value, $s] ; } else { push (@Bad, $key) } } if (@Bad) { my ($bad) = join(", ", @Bad) ; return $self->setError("unknown key value(s) @Bad") ; } return 1; } sub Compress::Raw::Lzma::Parameters::_checkType { my $self = shift ; my $key = shift ; my $value = shift ; my $type = shift ; my $validate = shift ; my $output = shift; #local $Carp::CarpLevel = $level ; #print "PARSE $type $key $value $validate $sub\n" ; if ( $type & Parse_store_ref) { #$value = $$value # if ref ${ $value } ; $$output = $value ; return 1; } $value = $$value ; if ($type & Parse_any) { $$output = $value ; return 1; } elsif ($type & Parse_unsigned) { return $self->setError("Parameter '$key' must be an unsigned int, got 'undef'") if $validate && ! defined $value ; return $self->setError("Parameter '$key' must be an unsigned int, got '$value'") if $validate && $value !~ /^\d+$/; $$output = defined $value ? $value : 0 ; return 1; } elsif ($type & Parse_signed) { return $self->setError("Parameter '$key' must be a signed int, got 'undef'") if $validate && ! defined $value ; return $self->setError("Parameter '$key' must be a signed int, got '$value'") if $validate && $value !~ /^-?\d+$/; $$output = defined $value ? $value : 0 ; return 1 ; } elsif ($type & Parse_boolean) { return $self->setError("Parameter '$key' must be an int, got '$value'") if $validate && defined $value && $value !~ /^\d*$/; $$output = defined $value ? $value != 0 : 0 ; return 1; } elsif ($type & Parse_string) { $$output = defined $value ? $value : "" ; return 1; } $$output = $value ; return 1; } sub Compress::Raw::Lzma::Parameters::parsed { my $self = shift ; my $name = shift ; return $self->{Got}{lc $name}[OFF_PARSED] ; } sub Compress::Raw::Lzma::Parameters::value { my $self = shift ; my $name = shift ; if (@_) { $self->{Got}{lc $name}[OFF_PARSED] = 1; $self->{Got}{lc $name}[OFF_DEFAULT] = $_[0] ; $self->{Got}{lc $name}[OFF_FIXED] = $_[0] ; } return $self->{Got}{lc $name}[OFF_FIXED] ; } sub Compress::Raw::Lzma::Encoder::STORABLE_freeze { my $type = ref shift; croak "Cannot freeze $type object\n"; } sub Compress::Raw::Lzma::Encoder::STORABLE_thaw { my $type = ref shift; croak "Cannot thaw $type object\n"; } @Compress::Raw::Lzma::EasyEncoder::ISA = qw(Compress::Raw::Lzma::Encoder); sub Compress::Raw::Lzma::EasyEncoder::new { my $pkg = shift ; my ($got) = ParseParameters(0, { 'AppendOutput' => [1, 1, Parse_boolean, 0], 'Bufsize' => [1, 1, Parse_unsigned, 16 * 1024], 'Preset' => [1, 1, Parse_unsigned, LZMA_PRESET_DEFAULT()], 'Extreme' => [1, 1, Parse_boolean, 0], 'Check' => [1, 1, Parse_unsigned, LZMA_CHECK_CRC32()], }, @_) ; # croak "Compress::Raw::Lzma::EasyEncoder::new: Bufsize must be >= 1, you specified " . # $got->value('Bufsize') # unless $got->value('Bufsize') >= 1; my $flags = 0 ; $flags |= FLAG_APPEND if $got->value('AppendOutput') ; my $preset = $got->value('Preset'); if ($got->value('Extreme')) { $preset |= LZMA_PRESET_EXTREME(); } lzma_easy_encoder($pkg, $flags, $got->value('Bufsize'), $preset, $got->value('Check')) ; } @Compress::Raw::Lzma::AloneEncoder::ISA = qw(Compress::Raw::Lzma::Encoder); sub Compress::Raw::Lzma::AloneEncoder::new { my $pkg = shift ; my ($got) = ParseParameters(0, { 'AppendOutput' => [1, 1, Parse_boolean, 0], 'Bufsize' => [1, 1, Parse_unsigned, 16 * 1024], 'Filter' => [1, 1, Parse_any, [] ], }, @_) ; my $flags = 0 ; $flags |= FLAG_APPEND if $got->value('AppendOutput') ; my $filters = Lzma::Filters::validateFilters(1, 0, $got->value('Filter')) ; # TODO - check max of 1 filter & it is a reference to Lzma::Filter::Lzma1 lzma_alone_encoder($pkg, $flags, $got->value('Bufsize'), $filters); } @Compress::Raw::Lzma::StreamEncoder::ISA = qw(Compress::Raw::Lzma::Encoder); sub Compress::Raw::Lzma::StreamEncoder::new { my $pkg = shift ; my ($got) = ParseParameters(0, { 'AppendOutput' => [1, 1, Parse_boolean, 0], 'Bufsize' => [1, 1, Parse_unsigned, 16 * 1024], 'Filter' => [1, 1, Parse_any, [] ], 'Check' => [1, 1, Parse_unsigned, LZMA_CHECK_CRC32()], }, @_) ; my $flags = 0 ; $flags |= FLAG_APPEND if $got->value('AppendOutput') ; my $filters = Lzma::Filters::validateFilters(1, 1, $got->value('Filter')) ; lzma_stream_encoder($pkg, $flags, $got->value('Bufsize'), $filters, $got->value('Check')); } @Compress::Raw::Lzma::RawEncoder::ISA = qw(Compress::Raw::Lzma::Encoder); sub Compress::Raw::Lzma::RawEncoder::new { my $pkg = shift ; my ($got) = ParseParameters(0, { 'ForZip' => [1, 1, Parse_boolean, 0], 'AppendOutput' => [1, 1, Parse_boolean, 0], 'Bufsize' => [1, 1, Parse_unsigned, 16 * 1024], 'Filter' => [1, 1, Parse_any, [] ], }, @_) ; my $flags = 0 ; $flags |= FLAG_APPEND if $got->value('AppendOutput') ; my $forZip = $got->value('ForZip'); my $filters = Lzma::Filters::validateFilters(1, ! $forZip, $got->value('Filter')) ; lzma_raw_encoder($pkg, $flags, $got->value('Bufsize'), $filters, $forZip); } @Compress::Raw::Lzma::AutoDecoder::ISA = qw(Compress::Raw::Lzma::Decoder); sub Compress::Raw::Lzma::AutoDecoder::new { my $pkg = shift ; my ($got) = ParseParameters(0, { 'AppendOutput' => [1, 1, Parse_boolean, 0], 'LimitOutput' => [1, 1, Parse_boolean, 0], 'ConsumeInput' => [1, 1, Parse_boolean, 1], 'Bufsize' => [1, 1, Parse_unsigned, 16 * 1024], 'MemLimit' => [1, 1, Parse_unsigned, 128 *1024 *1024], }, @_) ; my $flags = 0 ; $flags |= FLAG_APPEND if $got->value('AppendOutput') ; $flags |= FLAG_CONSUME_INPUT if $got->value('ConsumeInput') ; $flags |= FLAG_LIMIT_OUTPUT if $got->value('LimitOutput') ; lzma_auto_decoder($pkg, $flags, $got->value('MemLimit')); } @Compress::Raw::Lzma::AloneDecoder::ISA = qw(Compress::Raw::Lzma::Decoder); sub Compress::Raw::Lzma::AloneDecoder::new { my $pkg = shift ; my ($got) = ParseParameters(0, { 'AppendOutput' => [1, 1, Parse_boolean, 0], 'LimitOutput' => [1, 1, Parse_boolean, 0], 'ConsumeInput' => [1, 1, Parse_boolean, 1], 'Bufsize' => [1, 1, Parse_unsigned, 16 * 1024], 'MemLimit' => [1, 1, Parse_unsigned, 128 *1024 *1024], }, @_) ; my $flags = 0 ; $flags |= FLAG_APPEND if $got->value('AppendOutput') ; $flags |= FLAG_CONSUME_INPUT if $got->value('ConsumeInput') ; $flags |= FLAG_LIMIT_OUTPUT if $got->value('LimitOutput') ; lzma_alone_decoder($pkg, $flags, $got->value('Bufsize'), $got->value('MemLimit')); } @Compress::Raw::Lzma::StreamDecoder::ISA = qw(Compress::Raw::Lzma::Decoder); sub Compress::Raw::Lzma::StreamDecoder::new { my $pkg = shift ; my ($got) = ParseParameters(0, { 'AppendOutput' => [1, 1, Parse_boolean, 0], 'LimitOutput' => [1, 1, Parse_boolean, 0], 'ConsumeInput' => [1, 1, Parse_boolean, 1], 'Bufsize' => [1, 1, Parse_unsigned, 16 * 1024], 'MemLimit' => [1, 1, Parse_unsigned, 128 *1024 *1024], 'Flags' => [1, 1, Parse_unsigned, 0], }, @_) ; my $flags = 0 ; $flags |= FLAG_APPEND if $got->value('AppendOutput') ; $flags |= FLAG_CONSUME_INPUT if $got->value('ConsumeInput') ; $flags |= FLAG_LIMIT_OUTPUT if $got->value('LimitOutput') ; lzma_stream_decoder($pkg, $flags, $got->value('Bufsize'), $got->value('MemLimit'), $got->value('Flags')); } @Compress::Raw::Lzma::RawDecoder::ISA = qw(Compress::Raw::Lzma::Decoder); sub Compress::Raw::Lzma::RawDecoder::new { my $pkg = shift ; my ($got) = ParseParameters(0, { 'AppendOutput' => [1, 1, Parse_boolean, 0], 'LimitOutput' => [1, 1, Parse_boolean, 0], 'ConsumeInput' => [1, 1, Parse_boolean, 1], 'Bufsize' => [1, 1, Parse_unsigned, 16 * 1024], 'Filter' => [1, 1, Parse_any, [] ], 'Properties' => [1, 1, Parse_any, undef], }, @_) ; my $flags = 0 ; $flags |= FLAG_APPEND if $got->value('AppendOutput') ; $flags |= FLAG_CONSUME_INPUT if $got->value('ConsumeInput') ; $flags |= FLAG_LIMIT_OUTPUT if $got->value('LimitOutput') ; my $filters = Lzma::Filters::validateFilters(0, ! defined $got->value('Properties'), $got->value('Filter')) ; lzma_raw_decoder($pkg, $flags, $got->value('Bufsize'), $filters, $got->value('Properties')); } # LZMA1/2 # Preset # Dict # Lc # Lp # Pb # Mode LZMA_MODE_FAST, LZMA_MODE_NORMAL # Nice # Mf LZMA_MF_HC3 LZMA_MF_HC4 LZMA_MF_BT2 LZMA_MF_BT3 LZMA_MF_BT4 # Depth # BCJ # LZMA_FILTER_X86 # LZMA_FILTER_POWERPC # LZMA_FILTER_IA64 # LZMA_FILTER_ARM # LZMA_FILTER_ARMTHUMB # LZMA_FILTER_SPARC # # BCJ => LZMA_FILTER_X86 -- this assumes offset is 0 # BCJ => [LZMA_FILTER_X86, offset] # Delta # Dist 1 - 256, 1 # Subblock # Size # RLE # Align # Preset (0-9) LZMA_PRESET_EXTREME LZMA_PRESET_DEFAULT -- call lzma_lzma_preset # Memory # Check => LZMA_CHECK_NONE, LZMA_CHECK_CRC32, LZMA_CHECK_CRC64, LZMA_CHECK_SHA256 # my $bool = lzma_check_is_supported(LZMA_CHECK_CRC32); # my $int = lzma_check_size(LZMA_CHECK_CRC32); # my $int = $lzma->lzma_get_check(); #sub Compress::Raw::Lzma::new #{ # my $class = shift ; # my ($ptr, $status) = _new(@_); # return wantarray ? (undef, $status) : undef # unless $ptr ; # my $obj = bless [$ptr], $class ; # return wantarray ? ($obj, $status) : $obj; #} # #package Compress::Raw::UnLzma ; # #sub Compress::Raw::UnLzma::new #{ # my $class = shift ; # my ($ptr, $status) = _new(@_); # return wantarray ? (undef, $status) : undef # unless $ptr ; # my $obj = bless [$ptr], $class ; # return wantarray ? ($obj, $status) : $obj; #} sub Lzma::Filters::validateFilters { use UNIVERSAL ; use Scalar::Util qw(blessed ); my $encoding = shift; # not decoding my $lzma2 = shift; # my $objType = $lzma2 ? "Lzma::Filter::Lzma2" # : "Lzma::Filter::Lzma" ; my $objType = "Lzma::Filter::Lzma" ; # if only one, convert into an array reference if (blessed $_[0] ) { die "filter object $_[0] is not an $objType object" unless UNIVERSAL::isa($_[0], $objType); #$_[0] = [ $_[0] ] ; return [ $_[0] ] ; } if (ref $_[0] ne 'ARRAY') { die "$_[0] not Lzma::Filter object or ARRAY ref" } my $filters = $_[0] ; my $count = @$filters; # check number of filters die sprintf "Too many filters ($count), max is %d", LZMA_FILTERS_MAX() if $count > LZMA_FILTERS_MAX(); # TODO - add more tests here # Check that all filters inherit from Lzma::Filter # check that filters are supported # check memory requirements # need exactly one lzma1/2 filter # lzma1/2 is the last thing in the list for (my $i = 0; $i < @$filters ; ++$i) { my $filt = $filters->[$i]; die "filter is not an Lzma::Filter object" unless UNIVERSAL::isa($filt, 'Lzma::Filter'); die "Lzma filter must be last" if UNIVERSAL::isa($filt, 'Lzma::Filter::Lzma') && $i < $count -1 ; #die "xxx" unless lzma_filter_encoder_is_supported($filt->id()); } if (@$filters == 0) { push @$filters, $lzma2 ? Lzma::Filter::Lzma2() : Lzma::Filter::Lzma1(); } return $filters; } #package Lzma::Filter; #package Lzma::Filter::Lzma; #our ($VERSION, @ISA, @EXPORT, $AUTOLOAD); @Lzma::Filter::Lzma::ISA = qw(Lzma::Filter); sub Lzma::Filter::Lzma::mk { my $type = shift; my $got = Compress::Raw::Lzma::ParseParameters(0, { 'DictSize' => [1, 1, Parse_unsigned(), LZMA_DICT_SIZE_DEFAULT()], 'PresetDict' => [1, 1, Parse_string(), undef], 'Lc' => [1, 1, Parse_unsigned(), LZMA_LC_DEFAULT()], 'Lp' => [1, 1, Parse_unsigned(), LZMA_LP_DEFAULT()], 'Pb' => [1, 1, Parse_unsigned(), LZMA_PB_DEFAULT()], 'Mode' => [1, 1, Parse_unsigned(), LZMA_MODE_NORMAL()], 'Nice' => [1, 1, Parse_unsigned(), 64], 'Mf' => [1, 1, Parse_unsigned(), LZMA_MF_BT4()], 'Depth' => [1, 1, Parse_unsigned(), 0], }, @_) ; my $pkg = (caller(1))[3] ; my $DictSize = $got->value('DictSize'); die "Dictsize $DictSize not in range 4KiB - 1536Mib" if $DictSize < 1024 * 4 || $DictSize > 1024 * 1024 * 1536 ; my $Lc = $got->value('Lc'); die "Lc $Lc not in range 0-4" if $Lc < 0 || $Lc > 4; my $Lp = $got->value('Lp'); die "Lp $Lp not in range 0-4" if $Lp < 0 || $Lp > 4; die "Lc + Lp must be <= 4" if $Lc + $Lp > 4; my $Pb = $got->value('Pb'); die "Pb $Pb not in range 0-4" if $Pb < 0 || $Pb > 4; my $Mode = $got->value('Mode'); die "Mode $Mode not LZMA_MODE_FAST or LZMA_MODE_NORMAL" if $Mode != LZMA_MODE_FAST() && $Mode != LZMA_MODE_NORMAL(); my $Mf = $got->value('Mf'); die "Mf $Mf not valid" if ! grep { $Mf == $_ } ( LZMA_MF_HC3(), LZMA_MF_HC4(), LZMA_MF_BT2(), LZMA_MF_BT3(), LZMA_MF_BT4()); my $Nice = $got->value('Nice'); die "Nice $Nice not in range 2-273" if $Nice < 2 || $Nice > 273; my $obj = Lzma::Filter::Lzma::_mk($type, $DictSize, $Lc, $Lp, $Pb, $Mode, $Nice, $Mf, $got->value('Depth'), $got->value('PresetDict'), ); bless $obj, $pkg if defined $obj; $obj; } sub Lzma::Filter::Lzma::mkPreset { my $type = shift; my $preset = shift; my $pkg = (caller(1))[3] ; my $obj = Lzma::Filter::Lzma::_mkPreset($type, $preset); bless $obj, $pkg if defined $obj; $obj; } @Lzma::Filter::Lzma1::ISA = qw(Lzma::Filter::Lzma); sub Lzma::Filter::Lzma1 { Lzma::Filter::Lzma::mk(0, @_); } @Lzma::Filter::Lzma1::Preset::ISA = qw(Lzma::Filter::Lzma); sub Lzma::Filter::Lzma1::Preset { Lzma::Filter::Lzma::mkPreset(0, @_); } @Lzma::Filter::Lzma2::ISA = qw(Lzma::Filter::Lzma); sub Lzma::Filter::Lzma2 { Lzma::Filter::Lzma::mk(1, @_); } @Lzma::Filter::Lzma2::Preset::ISA = qw(Lzma::Filter::Lzma); sub Lzma::Filter::Lzma2::Preset { Lzma::Filter::Lzma::mkPreset(1, @_); } @Lzma::Filter::BCJ::ISA = qw(Lzma::Filter); sub Lzma::Filter::BCJ::mk { my $type = shift; my $got = Compress::Raw::Lzma::ParseParameters(0, { 'Offset' => [1, 1, Parse_unsigned(), 0], }, @_) ; my $pkg = (caller(1))[3] ; my $obj = Lzma::Filter::BCJ::_mk($type, $got->value('Offset')) ; bless $obj, $pkg if defined $obj; $obj; } @Lzma::Filter::X86::ISA = qw(Lzma::Filter::BCJ); sub Lzma::Filter::X86 { Lzma::Filter::BCJ::mk(LZMA_FILTER_X86(), @_); } @Lzma::Filter::PowerPC::ISA = qw(Lzma::Filter::BCJ); sub Lzma::Filter::PowerPC { Lzma::Filter::BCJ::mk(LZMA_FILTER_POWERPC(), @_); } @Lzma::Filter::IA64::ISA = qw(Lzma::Filter::BCJ); sub Lzma::Filter::IA64 { Lzma::Filter::BCJ::mk(LZMA_FILTER_IA64(), @_); } @Lzma::Filter::ARM::ISA = qw(Lzma::Filter::BCJ); sub Lzma::Filter::ARM { Lzma::Filter::BCJ::mk(LZMA_FILTER_ARM(), @_); } @Lzma::Filter::ARMThumb::ISA = qw(Lzma::Filter::BCJ); sub Lzma::Filter::ARMThumb { Lzma::Filter::BCJ::mk(LZMA_FILTER_ARMTHUMB(), @_); } @Lzma::Filter::Sparc::ISA = qw(Lzma::Filter::BCJ); sub Lzma::Filter::Sparc { Lzma::Filter::BCJ::mk(LZMA_FILTER_SPARC(), @_); } @Lzma::Filter::Delta::ISA = qw(Lzma::Filter); sub Lzma::Filter::Delta { #my $pkg = shift ; my ($got) = Compress::Raw::Lzma::ParseParameters(0, { 'Type' => [1, 1, Parse_unsigned, LZMA_DELTA_TYPE_BYTE()], 'Distance' => [1, 1, Parse_unsigned, LZMA_DELTA_DIST_MIN()], }, @_) ; Lzma::Filter::Delta::_mk($got->value('Type'), $got->value('Distance')) ; } #package Lzma::Filter::SubBlock; package Compress::Raw::Lzma; 1; __END__ =head1 NAME Compress::Raw::Lzma - Low-Level Perl Interface to lzma compression library =head1 SYNOPSIS use Compress::Raw::Lzma ; # Encoders my ($lz, $status) = new Compress::Raw::Lzma::EasyEncoder [OPTS] or die "Cannot create lzma object: $status\n"; my ($lz, $status) = new Compress::Raw::Lzma::AloneEncoder [OPTS] or die "Cannot create lzma object: $status\n"; my ($lz, $status) = new Compress::Raw::Lzma::StreamEncoder [OPTS] or die "Cannot create lzma object: $status\n"; my ($lz, $status) = new Compress::Raw::Lzma::RawEncoder [OPTS] or die "Cannot create lzma object: $status\n"; $status = $lz->code($input, $output); $status = $lz->flush($output); # Decoders my ($lz, $status) = new Compress::Raw::Lzma::AloneDecoder [OPTS] or die "Cannot create lzma object: $status\n"; my ($lz, $status) = new Compress::Raw::Lzma::AutoDecoder [OPTS] or die "Cannot create lzma object: $status\n"; my ($lz, $status) = new Compress::Raw::Lzma::StreamDecoder [OPTS] or die "Cannot create lzma object: $status\n"; my ($lz, $status) = new Compress::Raw::Lzma::RawDecoder [OPTS] or die "Cannot create lzma object: $status\n"; $status = $lz->code($input, $output); my $version = Compress::Raw::Lzma::lzma_version_number(); my $version = Compress::Raw::Lzma::lzma_version_string(); =head1 DESCRIPTION C provides an interface to the in-memory compression/uncompression functions from the lzma compression library. Although the primary purpose for the existence of C is for use by the C, C, C and C modules, it can be used on its own for simple compression/uncompression tasks. There are two functions, called C and C, used in all the compression and uncompression interfaces defined in this module. By default both of these functions overwrites any data stored in its output buffer parameter. If you want to compress/uncompress to a single buffer, and have C and C append to that buffer, enable the C option when you create the compression/decompression object. =head1 Compression There are four compression interfaces available in this module. =over 5 =item Compress::Raw::Lzma::EasyEncoder =item Compress::Raw::Lzma::AloneEncoder =item Compress::Raw::Lzma::StreamEncoder =item Compress::Raw::Lzma::RawEncoder =back =head2 ($z, $status) = new Compress::Raw::Lzma::EasyEncoder [OPTS]; Creates a new I compression object. If successful, it will return the initialised compression object, C<$z> and a C<$status> of C in a list context. In scalar context it returns the deflation object, C<$z>, only. If not successful, the returned compression object, C<$z>, will be I and C<$status> will hold the an I error code. Below is a list of the valid options: =over 5 =item B<< Preset => $preset >> Used to choose the compression preset. Valid values are 0-9 and C. 0 is the fastest compression with the lowest memory usage and the lowest compression. 9 is the slowest compression with the highest memory usage but with the best compression. Defaults to C. =item B<< Extreme => 0|1 >> Makes the compression a lot slower, but a small compression gain. Defaults to 0. =item B<< Check => $check >> Used to specify the integrity check used in the xz data stream. Valid values are C, C, C, C. Defaults to C. =item B<< AppendOutput => 0|1 >> Controls whether the compressed data is appended to the output buffer in the C and C methods. Defaults to 0. (Note in versions of this module prior to 2.072 the default value was incorrectly documented as 1). =item B<< BufSize => $number >> Sets the initial size for the output buffer used by the C<$d-Ecode> method. If the buffer has to be reallocated to increase the size, it will grow in increments of C. Defaults to 16k. =back =head2 ($z, $status) = new Compress::Raw::Lzma::AloneEncoder [OPTS]; Creates a legacy I compression object. This format is also know as lzma_alone. If successful, it will return the initialised compression object, C<$z> and a C<$status> of C in a list context. In scalar context it returns the deflation object, C<$z>, only. If not successful, the returned compression object, C<$z>, will be I and C<$status> will hold the an I error code. Below is a list of the valid options: =over 5 =item B<< Filter => $filter >> The C< $filter > option must be an object of type C. See L for a definition of C. If this option is not present an C object with default values will be used. =item B<< AppendOutput => 0|1 >> Controls whether the compressed data is appended to the output buffer in the C and C methods. Defaults to 0. (Note in versions of this module prior to 2.072 the default value was incorrectly documented as 1). =item B<< BufSize => $number >> Sets the initial size for the output buffer used by the C<$d-Ecode> method. If the buffer has to be reallocated to increase the size, it will grow in increments of C. Defaults to 16k. =back =head2 ($z, $status) = new Compress::Raw::Lzma::StreamEncoder [OPTS]; Creates a I compression object. If successful, it will return the initialised compression object, C<$z> and a C<$status> of C in a list context. In scalar context it returns the deflation object, C<$z>, only. If not successful, the returned compression object, C<$z>, will be I and C<$status> will hold the an I error code. Below is a list of the valid options: =over 5 =item B<< Filter => $filter >> =item B<< Filter => [$filter1, $filter2,...] >> This option is used to change the bahaviour of the StreamEncoder by applying between one and C filters to the data stream during compression. See L for more details on the available filters. If this option is present it must either contain a single C filter object or an array reference containing between one and C filter objects. If this option is not present an C object with default values will be used. =item B<< Check => $check >> Used to specify the integrity check used in the xz data stream. Valid values are C, C, C, C. Defaults to C. =item B<< AppendOutput => 0|1 >> Controls whether the compressed data is appended to the output buffer in the C and C methods. Defaults to 0. (Note in versions of this module prior to 2.072 the default value was incorrectly documented as 1). =item B<< BufSize => $number >> Sets the initial size for the output buffer used by the C<$d-Ecode> method. If the buffer has to be reallocated to increase the size, it will grow in increments of C. Defaults to 16k. =back =head2 ($z, $status) = new Compress::Raw::Lzma::RawEncoder [OPTS]; Low level access to lzma. If successful, it will return the initialised compression object, C<$z> and a C<$status> of C in a list context. In scalar context it returns the deflation object, C<$z>, only. If not successful, the returned compression object, C<$z>, will be I and C<$status> will hold the an I error code. Below is a list of the valid options: =over 5 =item B<< Filter => $filter >> =item B<< Filter => [$filter1, $filter2,...] >> This option is used to change the bahaviour of the RawEncoder by applying between one and C filters to the data stream during compression. See L for more details on the available filters. If this option is present it must either contain a single C filter object or an array reference containing between one and C filter objects. If this option is not present an C object with default values will be used. =item B<< AppendOutput => 0|1 >> Controls whether the compressed data is appended to the output buffer in the C and C methods. Defaults to 0. (Note in versions of this module prior to 2.072 the default value was incorrectly documented as 1). =item B<< BufSize => $number >> Sets the initial size for the output buffer used by the C<$d-Ecode> method. If the buffer has to be reallocated to increase the size, it will grow in increments of C. Defaults to 16k. =item B<< ForZip => 1/0 >> This boolean option is used to enable prefixing the compressed data stream with an encoded copy of the filter properties. Defaults to 0. =back =head2 $status = $lz->code($input, $output) Reads the contents of C<$input>, compresses it and writes the compressed data to C<$output>. Returns C on success and an C error code on failure. If C is enabled in the constructor for the lzma object, the compressed data will be appended to C<$output>. If not enabled, C<$output> will be truncated before the compressed data is written to it. =head2 $status = $lz->flush($output, LZMA_FINISH); Flushes any pending compressed data to C<$output>. By default it terminates the compressed data stream. Returns C on success and an C error code on failure. =head1 Compression examples =head2 Simple compression with EasyEncoder use strict; use warnings; use Compress::Raw::Lzma; my ($lz, $status) = Compress::Raw::Lzma::EasyEncoder->new( Preset => 6, Extreme => 0, ); die "Cannot create encoder: $status\n" unless $lz; my $input = "This is the data to compress " x 100; my $compressed = ''; $status = $lz->code($input, $compressed); die "Compression failed: $status\n" unless $status == LZMA_OK; $status = $lz->flush($compressed); die "Flush failed: $status\n" unless $status == LZMA_STREAM_END; print "Original size: ", length($input), "\n"; print "Compressed size: ", length($compressed), "\n"; =head2 Streaming compression with AppendOutput use strict; use warnings; use Compress::Raw::Lzma; my ($lz, $status) = Compress::Raw::Lzma::EasyEncoder->new( AppendOutput => 1, Preset => LZMA_PRESET_DEFAULT, ); die "Cannot create encoder: $status\n" unless $lz; my $compressed = ''; # Compress data in chunks for my $chunk ("Hello ", "world", "!") { $status = $lz->code($chunk, $compressed); die "Compression failed\n" unless $status == LZMA_OK; } # Finish compression $status = $lz->flush($compressed); die "Flush failed\n" unless $status == LZMA_STREAM_END; print "Compressed: ", length($compressed), " bytes\n"; =head2 Using custom filters with StreamEncoder use strict; use warnings; use Compress::Raw::Lzma; # Create a custom LZMA2 filter my $filter = Lzma::Filter::Lzma2( DictSize => 1024 * 1024 * 8, # 8MB dictionary Lc => 3, Lp => 0, Pb => 2, Mode => LZMA_MODE_NORMAL, Nice => 128, Mf => LZMA_MF_BT4, Depth => 512, ); my ($lz, $status) = Compress::Raw::Lzma::StreamEncoder->new( Filter => $filter, Check => LZMA_CHECK_SHA256, ); die "Cannot create encoder: $status\n" unless $lz; my $input = "Custom filter example data"; my $compressed = ''; $status = $lz->code($input, $compressed); $status = $lz->flush(compressed); =head2 Using multiple filters (BCJ + LZMA2) use strict; use warnings; use Compress::Raw::Lzma; # Combine BCJ filter for x86 binaries with LZMA2 compression my @filters = ( Lzma::Filter::X86(), # BCJ filter for x86 code Lzma::Filter::Lzma2(), # LZMA2 compression ); my ($lz, $status) = Compress::Raw::Lzma::StreamEncoder->new( Filter => \@filters, Check => LZMA_CHECK_CRC64, ); die "Cannot create encoder: $status\n" unless $lz; # ... compress binary data ... =head1 Uncompression There are four uncompression interfaces available in this module. =over 5 =item Compress::Raw::Lzma::AutoDecoder =item Compress::Raw::Lzma::AloneDecoder =item Compress::Raw::Lzma::StreamDecoder =item Compress::Raw::Lzma::RawDecoder =back =head2 ($z, $status) = new Compress::Raw::Lzma::AutoDecoder [OPTS] ; Create an object that can uncompress any of the compressed data streams that can be created by this module. If successful, it will return the initialised uncompression object, C<$z> and a C<$status> of C in a list context. In scalar context it returns the deflation object, C<$z>, only. If not successful, the returned uncompression object, C<$z>, will be I and C<$status> will hold the an I error code. Below is a list of the valid options: =over 5 =item B<-MemLimit> The number of bytes to use when uncompressing. Default is unlimited. =item B<-Bufsize> Sets the initial size for the output buffer used by the C<$i-Ecode> method. If the output buffer in this method has to be reallocated to increase the size, it will grow in increments of C. Default is 16k. =item B<-AppendOutput> This option controls how data is written to the output buffer by the C<$i-Ecode> method. If the option is set to false, the output buffer in the C<$i-Ecode> method will be truncated before uncompressed data is written to it. If the option is set to true, uncompressed data will be appended to the output buffer by the C<$i-Ecode> method. This option defaults to false. =item B<-ConsumeInput> If set to true, this option will remove compressed data from the input buffer of the C<< $i->code >> method as the uncompression progresses. This option can be useful when you are processing compressed data that is embedded in another file/buffer. In this case the data that immediately follows the compressed stream will be left in the input buffer. This option defaults to true. =item B<-LimitOutput> The C option changes the behavior of the C<< $i->code >> method so that the amount of memory used by the output buffer can be limited. When C is used the size of the output buffer used will either be the value of the C option or the amount of memory already allocated to C<$output>, whichever is larger. Predicting the output size available is tricky, so don't rely on getting an exact output buffer size. When C is not specified C<< $i->code >> will use as much memory as it takes to write all the uncompressed data it creates by uncompressing the input buffer. If C is enabled, the C option will also be enabled. This option defaults to false. =back =head2 ($z, $status) = new Compress::Raw::Lzma::AloneDecoder [OPTS] ; Create an object that can uncompress an lzma_alone data stream. If successful, it will return the initialised uncompression object, C<$z> and a C<$status> of C in a list context. In scalar context it returns the deflation object, C<$z>, only. If not successful, the returned uncompression object, C<$z>, will be I and C<$status> will hold the an I error code. Below is a list of the valid options: =over 5 =item B<-MemLimit> The number of bytes to use when uncompressing. Default is unlimited. =item B<-Bufsize> Sets the initial size for the output buffer used by the C<$i-Ecode> method. If the output buffer in this method has to be reallocated to increase the size, it will grow in increments of C. Default is 16k. =item B<-AppendOutput> This option controls how data is written to the output buffer by the C<$i-Ecode> method. If the option is set to false, the output buffer in the C<$i-Ecode> method will be truncated before uncompressed data is written to it. If the option is set to true, uncompressed data will be appended to the output buffer by the C<$i-Ecode> method. This option defaults to false. =item B<-ConsumeInput> If set to true, this option will remove compressed data from the input buffer of the C<< $i->code >> method as the uncompression progresses. This option can be useful when you are processing compressed data that is embedded in another file/buffer. In this case the data that immediately follows the compressed stream will be left in the input buffer. This option defaults to true. =item B<-LimitOutput> The C option changes the behavior of the C<< $i->code >> method so that the amount of memory used by the output buffer can be limited. When C is used the size of the output buffer used will either be the value of the C option or the amount of memory already allocated to C<$output>, whichever is larger. Predicting the output size available is tricky, so don't rely on getting an exact output buffer size. When C is not specified C<< $i->code >> will use as much memory as it takes to write all the uncompressed data it creates by uncompressing the input buffer. If C is enabled, the C option will also be enabled. This option defaults to false. =back =head2 $status = $z->code($input, $output); Uncompresses C<$input> and writes the uncompressed data to C<$output>. Returns C if the uncompression was successful, but the end of the compressed data stream has not been reached. Returns C on successful uncompression and the end of the compression stream has been reached. If C is enabled in the constructor for the lzma object, C<$input> will have all compressed data removed from it after uncompression. On C return this will mean that C<$input> will be an empty string; when C C<$input> will either be an empty string or will contain whatever data immediately followed the compressed data stream. If C is enabled in the constructor for the lzma object, the uncompressed data will be appended to C<$output>. If not enabled, C<$output> will be truncated before the uncompressed data is written to it. =head1 Uncompression examples =head2 Simple uncompression with AutoDecoder use strict; use warnings; use Compress::Raw::Lzma; # $compressed contains xz/lzma compressed data my $compressed = ...; my ($lz, $status) = Compress::Raw::Lzma::AutoDecoder->new( AppendOutput => 1, ConsumeInput => 1, ); die "Cannot create decoder: $status\n" unless $lz; my $uncompressed = ''; $status = $lz->code($compressed, $uncompressed); die "Decompression failed: $status\n" unless $status == LZMA_STREAM_END; print "Uncompressed size: ", length($uncompressed), "\n"; =head2 Streaming uncompression with LimitOutput use strict; use warnings; use Compress::Raw::Lzma; my ($lz, $status) = Compress::Raw::Lzma::AutoDecoder->new( LimitOutput => 1, ConsumeInput => 1, Bufsize => 4096, ); die "Cannot create decoder: $status\n" unless $lz; # Process compressed data in chunks my $compressed = ...; # your compressed data my $uncompressed = ''; while (length($compressed) > 0) { my $output = ''; $status = $lz->code($compressed, $output); $uncompressed .= $output; last if $status == LZMA_STREAM_END; die "Decompression error: $status\n" unless $status == LZMA_OK; } print "Total uncompressed: ", length($uncompressed), " bytes\n"; =head2 Uncompressing specific format with AloneDecoder use strict; use warnings; use Compress::Raw::Lzma; # For legacy .lzma format (lzma_alone) my ($lz, $status) = Compress::Raw::Lzma::AloneDecoder->new( MemLimit => 128 * 1024 * 1024, # 128 MB limit AppendOutput => 0, ); die "Cannot create decoder: $status\n" unless $lz; my $compressed = ...; # .lzma format data my $output = ''; $status = $lz->code($compressed, $output); die "Decompression failed: $status\n" unless $status == LZMA_STREAM_END; =head1 Filters A number of the Lzma compression interfaces (namely C & C) and the raw lzma uncompression interface make use of filters. These filters are used to change the behaviour of compression (and raw uncompression). All Lzma Filters are sub-classed from the C base-class. =head2 Lzma::Filter::Lzma The C class is the primary compression filter for LZMA algorithms. It provides fine-grained control over compression parameters. There are two subclasses of C, namely C and C. The former is typically used with C. The latter with C. When using Lzma filters an C I be included and it I be the last filter in the chain. There can only be one C filter in any filter chain. The C construction takes the following options. =over 5 =item DictSize => $value Dictionary size in bytes. This controls how many bytes of the recently processed uncompressed data is kept in memory. The size of the dictionary must be at least C. Defaults to C. =item PresetDict => $dict Provide an initial dictionary. This value is used to initialize the LZ77 history window. This feature only works correctly with raw encoding and decoding. You may not be able to decode other formats that have been encoded with a preset dictionary. C<$dict> should contain typical strings that occur in the files being compressed, with the most probably strings near the end fo the preset dictionary. If C<$dict> is larger than C, only the last C bytes are processed. =item Lc => $value Number of literal context bits. How many of the highest bits of the previous uncompressed eight-bit byte (also known as `literal') are taken into account when predicting the bits of the next literal. C<$value> must be a number between C and C. Note the sum of the C and C options cannot exceed 4. Defaults to C. =item Lp => $value Number of literal position bits. How many of the lowest bits of the current position (number of bytes from the beginning of the uncompressed data) in the uncompressed data is taken into account when predicting the bits of the next literal (a single eight-bit byte). Defaults to C. =item Pb => $value Number of position bits How many of the lowest bits of the current position in the uncompressed data is taken into account when estimating probabilities of matches. A match is a sequence of bytes for which a matching sequence is found from the dictionary and thus can be stored as distance-length pair. C<$value> must be a number between C and C. Defaults to C. =item Mode => $value The Compression Mode. Valid values are C and C. Defaults to C. =item Nice => $value Nice length of a match Defaults to 64. =item Mf => $value Defines which Match Finder to use. Valid values are C C, C C and C. Defaults to C. =item Depth => $value Maximum search depth in the match finder. Defaults to 0. =back =head2 Lzma::Filter::BCJ The sub-classes of C are the Branch/Call/Jump conversion filters. These filters are used to rewrite executable binary code for a number of processor architectures. None of these classes take any options. =over 5 =item Lzma::Filter::X86 Filter for x86 binaries. =item Lzma::Filter::PowerPC Filter for Big endian PowerPC binaries. =item Lzma::Filter::IA64 Filter for IA64 (Itanium) binaries. =item Lzma::Filter::ARM Filter for ARM binaries. =item Lzma::Filter::ARMThumb Filter for ARMThumb binaries. =item Lzma::Filter::Sparc Filter for Sparc binaries. =back =head2 Lzma::Filter::Delta Usage is Lzma::Filter::Delta [OPTS] =over 5 =item Type => $type Defines the type of Delta calculation. The only available type (and therefore the default) is C, =item Distance => $value Defines the Delta Distance. C<$value> must be a number between C and C. Default is C. =back =head1 Filter examples =head2 Using LZMA2 filter with custom dictionary size use strict; use warnings; use Compress::Raw::Lzma; # Create LZMA2 filter with large dictionary for better compression my $filter = Lzma::Filter::Lzma2( DictSize => 16 * 1024 * 1024, # 16 MB dictionary Lc => 3, Lp => 0, Pb => 2, ); my ($lz, $status) = Compress::Raw::Lzma::StreamEncoder->new( Filter => $filter, Check => LZMA_CHECK_CRC64, ); die "Cannot create encoder: $status\n" unless $lz; my $input = "Data to compress..."; my $output = ''; $lz->code($input, $output); $lz->flush($output); =head2 Using LZMA1 filter for legacy .lzma format use strict; use warnings; use Compress::Raw::Lzma; # LZMA1 is used for the legacy .lzma format my $filter = Lzma::Filter::Lzma1( DictSize => 8 * 1024 * 1024, Mode => LZMA_MODE_NORMAL, Mf => LZMA_MF_BT4, Nice => 273, ); my ($lz, $status) = Compress::Raw::Lzma::AloneEncoder->new( Filter => $filter, ); die "Cannot create encoder: $status\n" unless $lz; =head2 Using preset-based LZMA2 filter use strict; use warnings; use Compress::Raw::Lzma; # Use preset instead of manually configuring parameters # Preset 9 = maximum compression my $filter = Lzma::Filter::Lzma2::Preset(9 | LZMA_PRESET_EXTREME); my ($lz, $status) = Compress::Raw::Lzma::StreamEncoder->new( Filter => $filter, ); die "Cannot create encoder: $status\n" unless $lz; =head2 Combining Delta filter with LZMA2 use strict; use warnings; use Compress::Raw::Lzma; # Delta filter is useful for data with small changes between bytes # (e.g., uncompressed images, audio samples) my @filters = ( Lzma::Filter::Delta( Type => LZMA_DELTA_TYPE_BYTE, Distance => 1, ), Lzma::Filter::Lzma2( DictSize => 8 * 1024 * 1024, ), ); my ($lz, $status) = Compress::Raw::Lzma::StreamEncoder->new( Filter => \@filters, Check => LZMA_CHECK_CRC32, ); die "Cannot create encoder: $status\n" unless $lz; # Compress image or audio data my $raw_data = ...; my $compressed = ''; $lz->code($raw_data, $compressed); $lz->flush($compressed); =head2 Using BCJ filter for x86 executable compression use strict; use warnings; use Compress::Raw::Lzma; # BCJ (Branch/Call/Jump) filter optimizes compression of x86 binaries my @filters = ( Lzma::Filter::X86(Offset => 0), Lzma::Filter::Lzma2(), ); my ($lz, $status) = Compress::Raw::Lzma::StreamEncoder->new( Filter => \@filters, Check => LZMA_CHECK_SHA256, ); die "Cannot create encoder: $status\n" unless $lz; # Read and compress x86 binary open my $fh, '<', 'program.exe' or die $!; binmode $fh; my $binary = do { local $/; <$fh> }; close $fh; my $compressed = ''; $lz->code($binary, $compressed); $lz->flush($compressed); print "Original: ", length($binary), " bytes\n"; print "Compressed: ", length($compressed), " bytes\n"; =head2 Using ARM filter for ARM binaries use strict; use warnings; use Compress::Raw::Lzma; # For ARM executables my @filters = ( Lzma::Filter::ARM(), Lzma::Filter::Lzma2( DictSize => 4 * 1024 * 1024, ), ); my ($lz, $status) = Compress::Raw::Lzma::StreamEncoder->new( Filter => \@filters, ); die "Cannot create encoder: $status\n" unless $lz; =head2 Maximum compression with multiple filters use strict; use warnings; use Compress::Raw::Lzma; # Combine filters for maximum compression my @filters = ( Lzma::Filter::Delta(Distance => 1), Lzma::Filter::Lzma2( DictSize => 64 * 1024 * 1024, # 64 MB Lc => 4, Lp => 0, Pb => 2, Mode => LZMA_MODE_NORMAL, Nice => 273, Mf => LZMA_MF_BT4, Depth => 1024, ), ); my ($lz, $status) = Compress::Raw::Lzma::StreamEncoder->new( Filter => \@filters, Check => LZMA_CHECK_SHA256, ); die "Cannot create encoder: $status\n" unless $lz; =head1 Misc =head2 my $version = Compress::Raw::Lzma::lzma_version_number(); Returns the version of the underlying lzma library this module is using at run-time as a number. =head2 my $version = Compress::Raw::Lzma::lzma_version_string(); Returns the version of the underlying lzma library this module is using at run-time as a string. =head2 my $version = Compress::Raw::Lzma::LZMA_VERSION(); Returns the version of the underlying lzma library this module was using at compile-time as a number. =head2 my $version = Compress::Raw::Lzma::LZMA_VERSION_STRING(); Returns the version of the underlying lzma library this module was using at compile-time as a string. =head1 Constants The following lzma constants are exported by this module. =head2 Return/Status Codes =over 5 =item LZMA_OK Operation completed successfully. =item LZMA_STREAM_END End of stream was reached. The complete compressed data has been decoded/encoded. =item LZMA_NO_CHECK Input stream has no integrity check. =item LZMA_UNSUPPORTED_CHECK Cannot calculate the integrity check (not supported by this build). =item LZMA_GET_CHECK Integrity check type is now available. =item LZMA_MEM_ERROR Cannot allocate memory. =item LZMA_MEMLIMIT_ERROR Memory usage limit was reached. =item LZMA_FORMAT_ERROR File format not recognized. =item LZMA_OPTIONS_ERROR Invalid or unsupported options. =item LZMA_DATA_ERROR Data is corrupt. =item LZMA_BUF_ERROR No progress is possible (stream is truncated or corrupt). =item LZMA_PROG_ERROR Programming error (should never happen in correct usage). =back =head2 Flush Modes =over 5 =item LZMA_RUN Continue coding. Used for normal operation. =item LZMA_SYNC_FLUSH Make all the input available at output. Not commonly used with LZMA. =item LZMA_FULL_FLUSH Finish encoding of the current Block. Not commonly used. =item LZMA_FINISH Finish the coding operation. All input must have been given to the encoder. =back =head2 Integrity Check Types =over 5 =item LZMA_CHECK_NONE No Check is calculated. =item LZMA_CHECK_CRC32 CRC32 using the polynomial from IEEE-802.3. =item LZMA_CHECK_CRC64 CRC64 using the polynomial from ECMA-182. =item LZMA_CHECK_SHA256 SHA-256 checksum. =item LZMA_CHECK_ID_MAX Maximum valid Check ID. =item LZMA_CHECK_SIZE_MAX Maximum size of any Check algorithm. =back =head2 Preset and Compression Level =over 5 =item LZMA_PRESET_DEFAULT Default compression preset (currently 6). =item LZMA_PRESET_LEVEL_MASK Mask for preset level (0-9). =item LZMA_PRESET_EXTREME Extreme compression preset flag. Can be combined with preset level using bitwise OR (e.g., C<6 | LZMA_PRESET_EXTREME>). =back =head2 Stream Flags =over 5 =item LZMA_TELL_NO_CHECK Accept streams with no integrity check. =item LZMA_TELL_UNSUPPORTED_CHECK Accept streams with unsupported integrity check. =item LZMA_TELL_ANY_CHECK Accept any type of integrity check. =item LZMA_CONCATENATED Enable support for concatenated streams. =back =head2 Match Finder Types =over 5 =item LZMA_MF_HC3 Hash Chain with 3 byte hashing. =item LZMA_MF_HC4 Hash Chain with 4 byte hashing. =item LZMA_MF_BT2 Binary Tree with 2 byte hashing. =item LZMA_MF_BT3 Binary Tree with 3 byte hashing. =item LZMA_MF_BT4 Binary Tree with 4 byte hashing (default and recommended). =back =head2 Compression Mode =over 5 =item LZMA_MODE_FAST Fast compression mode. =item LZMA_MODE_NORMAL Normal compression mode (default). =back =head2 Dictionary and Parameter Limits =over 5 =item LZMA_DICT_SIZE_MIN Minimum dictionary size (4 KiB). =item LZMA_DICT_SIZE_DEFAULT Default dictionary size. =item LZMA_LCLP_MIN Minimum for lc and lp (0). =item LZMA_LCLP_MAX Maximum for lc and lp (4). =item LZMA_LC_DEFAULT Default number of literal context bits (3). =item LZMA_LP_DEFAULT Default number of literal position bits (0). =item LZMA_PB_MIN Minimum number of position bits (0). =item LZMA_PB_MAX Maximum number of position bits (4). =item LZMA_PB_DEFAULT Default number of position bits (2). =back =head2 BCJ (Branch/Call/Jump) Filters Architecture-specific filters for executable code: =over 5 =item LZMA_FILTER_X86 Filter for x86 (32-bit and 64-bit) binaries. =item LZMA_FILTER_POWERPC Filter for Big endian PowerPC binaries. =item LZMA_FILTER_IA64 Filter for IA-64 (Itanium) binaries. =item LZMA_FILTER_ARM Filter for ARM binaries. =item LZMA_FILTER_ARMTHUMB Filter for ARM-Thumb binaries. =item LZMA_FILTER_SPARC Filter for SPARC binaries. =back =head2 Delta Filter =over 5 =item LZMA_FILTER_DELTA Delta filter ID. =item LZMA_DELTA_TYPE_BYTE Byte-wise delta calculation. =item LZMA_DELTA_DIST_MIN Minimum delta distance (1). =item LZMA_DELTA_DIST_MAX Maximum delta distance (256). =back =head2 LZMA Filters =over 5 =item LZMA_FILTER_LZMA2 LZMA2 filter (used in .xz format). =item LZMA_FILTERS_MAX Maximum number of filters in a chain (4). =back =head2 Stream Header and Block =over 5 =item LZMA_STREAM_HEADER_SIZE Size of Stream Header (12 bytes). =item LZMA_BLOCK_HEADER_SIZE_MIN Minimum size of Block Header. =item LZMA_BLOCK_HEADER_SIZE_MAX Maximum size of Block Header. =item LZMA_BACKWARD_SIZE_MIN Minimum Backward Size. =back =head2 Version Information =over 5 =item LZMA_VERSION Encoded version number of liblzma. =item LZMA_VERSION_MAJOR Major version number. =item LZMA_VERSION_MINOR Minor version number. =item LZMA_VERSION_PATCH Patch version number. =item LZMA_VERSION_STABILITY Stability indicator. =item LZMA_VERSION_STABILITY_STRING Stability as string (e.g., "alpha", "beta", "stable"). =item LZMA_VERSION_STRING Full version string. =back =head1 SUPPORT General feedback/questions/bug reports should be sent to L (preferred) or L. =head1 SEE ALSO L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L, L L L, L, L, L =head1 AUTHOR This module was written by Paul Marquess, C. =head1 MODIFICATION HISTORY See the Changes file. =head1 COPYRIGHT AND LICENSE Copyright (c) 2005-2026 Paul Marquess. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.