Apache2-SSI

 view release on metacpan or  search on metacpan

lib/Apache2/SSI/File/Type.pm  view on Meta::CPAN

            return( $self->{default_type} ? $self->{default_type} : 'application/x-unknown' );
        }
    }
    
    # Current file handle. or undef if check_magic (-c option) is true.
    my $io;
    $io = IO::File->new( "<$file" ) || do
    {
        if( $self->{error_returns_undef} )
        {
            return( $self->error( "Unable to open file '$file': $!" ) );
        }
        else
        {
            return( "x-system/x-error; $base_file: $!" );
        }
    };
    $io->binmode;
    
    # 3) Check for script
    # if( ( -x( $file ) || ( $^O =~ /^(dos|mswin32|NetWare|symbian|win32)$/i && $file =~ /\.(?:pl|cgi)$/ ) ) && 
#     if( ( -x( $file ) || $file =~ /\.(?:cgi|pl|t)$/ ) && 
#         -T( _ ) ) 
    my $default;
    if( -x( $file ) && -T( _ ) ) 
    {
        # Note, some magic files include elaborate attempts to match #! header lines 
        # and return pretty responses but this slows down matching and is unnecessary.
        my $line1 = $io->getline;
        if( $line1 =~ /^\#![[:blank:]\h]*(\S+)/ ) 
        {
            # Returns the binary name, without file path
            my $bin_name = File::Basename::basename( $1 );
            #$desc .= " executable $bin_name script text";
            # $io->close;
            # return( "text/x-${bin_name}" );
            $default = "text/x-${bin_name}";
        }
    }
    my $out = $self->handle( $io, $desc, { default => $default } );
    $io->close;
    return( $out );
}

sub follow_links { return( shift->_set_get_boolean( 'follow_links', @_ ) ); }

sub handle 
{
    my $self = shift( @_ );
    my $io = shift( @_ );
    my $desc = shift( @_ );
    my $opts = $self->_get_args_as_hash( @_ );
    $opts->{default} = $self->default_type if( !length( $opts->{default} ) );
    my $type = '';
    
    # 3) Iterate over each magic entry.
    my $match_found = 0;
    for( my $m = 0; $m <= $#{ $self->{magic_data} }; $m++ ) 
    {
        # Check if the m-th magic entry matches and if it does, then $desc will contain 
        # an updated description
        my $test;
        if( ( $test = $self->_magic_match( $self->{magic_data}->[$m], \$desc, $io ) ) ) 
        {
            if( defined( $desc ) && $desc ne '' ) 
            {
                $match_found = 1;
                $type = $desc;
                last;
            }
        }
        elsif( !defined( $test ) )
        {
            warnings::warn( "Error occurred while checking for match: ", $self->error ) if( warnings::enabled() && $self->debug );
        }
    
        # Read another entry from the magic file if we've exhausted all the entries 
        # already buffered. read_magic_entry will add to the end of the array 
        # if there are more.
        if( $m == $#{ $self->{magic_data} } &&
            $self->{magic}->{io} && 
            !$self->{magic}->{io}->eof )
        {
            $self->read_magic_entry();
        }
    }
    
    # 4) Check if it's text or binary.
    # if It's text, then do a bunch of searching for special tokens
    if( !$match_found ) 
    {
        my $data = '';
        $io->seek( 0, 0 );
        $io->read( $data, 0x8564 );
        $type = $self->with_data( $data );
    }
    if( !defined( $type ) )
    {
        $type = $opts->{default} ? $opts->{default} : '';
    }
    return( $type );
}

sub parse_magic_file 
{
    my $self = shift( @_ );
    my $io   = shift( @_ );
    # Initialize values
    $self->{magic}->{io}     = $io;
    $self->{magic}->{buffer} = undef();
    $self->{magic}->{count}  = 0;
    while( !$io->eof() )
    {
        $self->read_magic_entry();
    }
    seek( $io, 0, 0 );
}

# parse_magic_line( $line, $line_num, $subtests )
#
# Parses the match info out of $line.  Returns a reference to an array.

lib/Apache2/SSI/File/Type.pm  view on Meta::CPAN

        my( $token, %val );
        foreach my $type ( keys( %{$self->{SPECIALS}} ) ) 
        {
            my $token = '(' . ( join( '|', sort{ length( $a ) <=> length( $b ) } @{$self->{SPECIALS}->{ $type } } ) ) . ')';
            my $tdata = $data;
            if( $tdata =~ /$token/mg ) 
            {
                $val{ $type } = pos( $tdata );
            }
        }
        # Search latest match
        if( scalar( keys( %val ) ) )
        {
            my @skeys = sort{ $val{ $a } <=> $val{ $b } } keys( %val );
            $type = $skeys[0];
        }
    
        # ALLDONE:
        # $type = 'text/plain' if( !defined( $type ) );
    }
    # $type = 'text/plain' if( !defined( $type ) );
    return( $type );
}

sub with_filename 
{
    my $self  = shift( @_ );
    my $fname = shift( @_ );
    my $type  = '';
    
    my $file = $fname;
    $fname =~ s/^.*\///;
    for my $regex ( keys( %{$self->{FILE_EXTS}} ) )
    {
        if( $fname =~ /$regex/i ) 
        {
            if( ( defined( $type ) && $type !~ /;/ ) || 
                !defined( $type ) ) 
            {
                # has no x-type param
                $type = $self->{FILE_EXTS}->{ $regex };
            }
        }
    }
    return( $type );
}

sub with_magic 
{
    my $self = shift( @_ );
    my $data = shift( @_ );
    my $desc = '';
    my $type = '';
    
    return( 'application/octet-stream' ) if( length( $data ) <= 0 );
    
    # 3) Iterate over each magic entry.
    for( my $m = 0; $m <= $#{ $self->{magic_data} }; $m++ ) 
    {
        # Check if the m-th magic entry matches and if it does, then $desc will contain 
        # an updated description
        if( $self->_magic_match_str( $self->{magic_data}->[ $m ], \$desc, $data ) ) 
        {
            if( defined( $desc ) && $desc ne '' ) 
            {
                $type = $desc;
                last;
            }
        }
    
        # Read another entry from the magic file if we've exhausted all the entries 
        # already buffered. read_magic_entry will add to the end of the array if 
        # there are more.
        if( $m == $#{ $self->{magic_data} } && !$self->{magic}->{io}->eof() )
        {
            $self->read_magic_entry();
        }
    }
    return( $type );
}

sub _is_binary 
{
    my( $data ) = @_;
    my $len = length( $data );
    # Exclude TAB, ESC, nl, cr
    my $count = ( $data =~ tr/[\x00-\x08\x0b-\x0c\x0e-\x1a\x1c-\x1f]// );
    # No contents
    return( 1 ) if( $len <= 0 );
    # Binary
    return( 1 ) if( ( $count / $len ) > 0.1 );
    return( 0 );
}

# Compare the magic item with the filehandle.
# If success, print info and return true, otherwise return undef.
#
# This is called recursively if an item has subitems.
sub _magic_match
{
    my $self = shift( @_ );
    # $io is the file handle of the file being inspected
    my( $item, $p_desc, $io ) = @_;
    
    # $item could be undef if we ran into troubles while reading the entry.
    return unless( defined( $item ) && ref( $item // '' ) eq 'ARRAY' );
    
    # Delayed evaluation. If this is our first time considering this item, then parse out 
    # its structure. @$item is just the raw string, line number, and subtests until we 
    # need the real info. This saves time otherwise wasted parsing unused subtests.
    $item = $self->parse_magic_line( @$item ) if( @$item == 3 );
    
    # $io is not defined if -c. That way we always return false for every item which 
    # allows reading/checking the entire magic file.
    return( $self->error( "File handle is not defined." ) ) unless( defined( $io ) );
    # return unless( defined( fileno( $io ) ) );
    # return unless( Scalar::Util::openhandle( $io ) );
    
    my( $offtype, $offset, $numbytes, $type, $mask, $op, $testval, $template, $message, $subtests ) = @$item;
    $self->{trick}++;
    if( $self->{trick} > 186 && $self->{trick} < 192 )



( run in 1.921 second using v1.01-cache-2.11-cpan-39bf76dae61 )