using Archive::Zip::MemberRead fails to find "opened" method

Discussion in 'Perl Misc' started by David Karr, Jun 6, 2012.

  1. David Karr

    David Karr Guest

    I'm working on a script that can recursively examine archive files, so I'm using "Archive::Zip" along with "Archive::Zip::MemberRead". I had originally written it with just "Archive::Zip", and it was working fine, but I tried to extend it to recursively examine the archive by adding "MemberRead".

    I'm seeing the following error now:

    Can't locate object method "opened" via package "Archive::Zip::MemberRead" at /usr/local/share/perl/5.14.2/Archive/Zip/Archive.pm line 570.

    I tried adding in my script the various "File::" imports that are in "Archive.pm", but that made no difference.
    David Karr, Jun 6, 2012
    #1
    1. Advertising

  2. * David Karr wrote in comp.lang.perl.misc:
    >Subject: using Archive::Zip::MemberRead fails to find "opened" method


    http://search.cpan.org/dist/Archive-Zip/lib/Archive/Zip/MemberRead.pm
    does not seem to have any "opened" method, so you are probably calling
    the wrong method, or the right method on the wrong object (or the wrong
    method on the wrong object, if you want to be pedantic).
    --
    Björn Höhrmann · mailto: · http://bjoern.hoehrmann.de
    Am Badedeich 7 · Telefon: +49(0)160/4415681 · http://www.bjoernsworld.de
    25899 Dagebüll · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/
    Bjoern Hoehrmann, Jun 7, 2012
    #2
    1. Advertising

  3. David Karr

    David Karr Guest

    On Thursday, June 7, 2012 1:28:16 AM UTC-7, Ben Morrow wrote:
    > Quoth David Karr <>:
    > > I'm working on a script that can recursively examine archive files, so
    > > I'm using "Archive::Zip" along with "Archive::Zip::MemberRead". I had
    > > originally written it with just "Archive::Zip", and it was working fine,
    > > but I tried to extend it to recursively examine the archive by adding
    > > "MemberRead".
    > >
    > > I'm seeing the following error now:
    > >
    > > Can't locate object method "opened" via package
    > > "Archive::Zip::MemberRead" at
    > > /usr/local/share/perl/5.14.2/Archive/Zip/Archive.pm line 570.

    >
    > That implies you are calling ->readFromFileHandle on an Archive. You
    > need to be calling ->readFileHandle on a Member; but this method won't
    > exist unless you
    >
    > use Archive::Zip::MemberRead;


    Ok, based on that input, this is what I have so far. It's not failing, but I don't think it's working properly either. I ran this on an archive that has an archive which has an element I'm searching for, but it didn't find it.

    sub processArchive($$$) {
    my ($zip, $match, $zipName) = @_;
    my @matchingList = $zip->membersMatching($match);
    my $len = @matchingList;
    if ($len > 0) {
    print $zipName . ":\n";
    if ($opt_list == 0) {
    for my $member (@matchingList) {
    if ($opt_cat == 0) {
    print $member->fileName() . getDetail($member) . "\n";
    }
    else {
    print $member->fileName() . getDetail($member) . ":\n";
    print $member->contents();
    }
    }
    }
    }
    my @matchingArchiveList = $zip->membersMatching("\.jar");
    my $archivesLen = @matchingArchiveList;
    #print "archivesLen[" . $archivesLen . "]\n";
    if ($archivesLen > 0) {
    print "zipfile[" . $zipName . "]\n";
    for my $archiveMember (@matchingArchiveList) {
    print "archiveMember[" . $archiveMember->fileName() . "]\n";
    my $zipfh = Archive::Zip::MemberRead->new($zip, $archiveMember);
    my $archiveZip = Archive::Zip->new();
    my $archiveStatus = $archiveMember->readFileHandle($zipfh);
    print "archiveStatus[" . $archiveStatus . "]\n";
    # if ($archiveStatus == AZ_OK) {
    processArchive($archiveZip, $entry, $zipName . ":" . $archiveMember->fileName());
    # }
    }
    }
    }

    >
    > > I tried adding in my script the various "File::" imports that are in
    > > "Archive.pm", but that made no difference.

    >
    > Why on Earth would you do that?


    Have you ever done anything that you knew didn't make any sense, but you didn't know what else to try?
    David Karr, Jun 7, 2012
    #3
  4. Ben Morrow <> writes:

    [...]

    >> > > I tried adding in my script the various "File::" imports that are in
    >> > > "Archive.pm", but that made no difference.
    >> >
    >> > Why on Earth would you do that?

    >>
    >> Have you ever done anything that you knew didn't make any sense, but you
    >> didn't know what else to try?

    >
    > I have, but it never helps. Without understanding the cause of the
    > problem you've got no way of knowing you've fixed it, which means it'll
    > probably come back.


    You seem to live in a part of the universe where 'sales rep' "computer
    experts" don't exist ...
    Rainer Weikusat, Jun 7, 2012
    #4
  5. David Karr

    David Karr Guest

    On Thursday, June 7, 2012 12:01:05 PM UTC-7, Ben Morrow wrote:
    > Quoth David Karr <>:
    > > On Thursday, June 7, 2012 1:28:16 AM UTC-7, Ben Morrow wrote:
    > > > Quoth David Karr <>:
    > > > > I'm working on a script that can recursively examine archive files,so
    > > > > I'm using "Archive::Zip" along with "Archive::Zip::MemberRead". I had
    > > > > originally written it with just "Archive::Zip", and it was working fine,
    > > > > but I tried to extend it to recursively examine the archive by adding
    > > > > "MemberRead".
    > > > >
    > > > > I'm seeing the following error now:
    > > > >
    > > > > Can't locate object method "opened" via package
    > > > > "Archive::Zip::MemberRead" at
    > > > > /usr/local/share/perl/5.14.2/Archive/Zip/Archive.pm line 570.
    > > >
    > > > That implies you are calling ->readFromFileHandle on an Archive. You
    > > > need to be calling ->readFileHandle on a Member; but this method won't
    > > > exist unless you
    > > >
    > > > use Archive::Zip::MemberRead;

    > <snip>
    > >
    > > for my $archiveMember (@matchingArchiveList) {
    > > print "archiveMember[" . $archiveMember->fileName() . "]\n";
    > > my $zipfh = Archive::Zip::MemberRead->new($zip, $archiveMember);
    > > my $archiveZip = Archive::Zip->new();
    > > my $archiveStatus = $archiveMember->readFileHandle($zipfh);

    >
    > Oh, I see now what you are doing: you did want
    >
    > my $archiveStatus = $archiveZip->readFromFileHandle($zipfh);
    >
    > after all, but unfortunately it isn't going to work. AZ::MemberRead
    > doesn't give you a real filehandle: the object is neither a Perl
    > filehandle nor inherits from IO::Handle, so AZ can't read a zipfile from
    > it.
    >
    > If you felt like it writing a tied-handle class (or a proper subclass of
    > IO::Handle) which read from an AZ::Member shouldn't be too difficult.
    > You would need to implement seeking by calling ->rewindData and then
    > reading forward, since AZ needs to be able to seek; you would also need
    > to count bytes read so as to return the correct value from tell. A tied
    > handle would probably be easiest: see perltie and Tie::Handle.


    That sounds more complicated than my backup plan, which is just to extract the member to a tempfile and then reading it as an archive. I had already implemented that, as a result of responses to a related question I had asked. This mostly worked, but I noticed some situations where it didn't work,so I thought I would return back to the hopefully more efficient mechanismI asked about in this chain. Now that I see this is more complicated thanI'm comfortable, I returned to try to fix the tempfile strategy, and I gotthat working.

    This is the key part of it:

    for my $archiveMember (@matchingArchiveList) {
    #print "archiveMember[" . $archiveMember->fileName() . "]\n";
    my $tempArchiveName = prepareTempFile();
    #print "tempArchiveName[" . $tempArchiveName . "]\n";
    $zip->extractMemberWithoutPaths($archiveMember, $tempArchiveName);
    my $archiveZip = Archive::Zip->new();
    my $archiveStatus = $archiveZip->read($tempArchiveName);
    if ($archiveStatus == AZ_OK) {
    processArchive($archiveZip, $entry, $zipName . ":" . $archiveMember->fileName());
    unlink($tempArchiveName);
    }
    }

    Again, this appears to work. I'm sure this is likely a little slower than the other approach, but it's not noticeable for me, so it's good enough.

    Do you see any problems with this approach?
    David Karr, Jun 7, 2012
    #5
  6. David Karr

    David Karr Guest

    On Thursday, June 7, 2012 4:02:20 PM UTC-7, Ben Morrow wrote:
    > Quoth David Karr <>:
    > >
    > > This is the key part of it:
    > >
    > > for my $archiveMember (@matchingArchiveList) {
    > > #print "archiveMember[" . $archiveMember->fileName() . "]\n";
    > > my $tempArchiveName = prepareTempFile();
    > > #print "tempArchiveName[" . $tempArchiveName . "]\n";
    > > $zip->extractMemberWithoutPaths($archiveMember, $tempArchiveName);
    > > my $archiveZip = Archive::Zip->new();
    > > my $archiveStatus = $archiveZip->read($tempArchiveName);
    > > if ($archiveStatus == AZ_OK) {
    > > processArchive($archiveZip, $entry, $zipName . ":" .
    > > $archiveMember->fileName());
    > > unlink($tempArchiveName);

    >
    > This unlink probably wants to be outside the if. If (say) the internal
    > zipfile is corrupted, and can't be read, you still need to clean up the
    > tempfile.


    I was thinking about that, but I assume that it would fail if the file didn't actually get created? I figured I would need some sort of exception handling to do that cleanly (of course, if that was really important, I probably should have already been doing that). I'm not very familiar with how Perl does exception handling.
    David Karr, Jun 8, 2012
    #6
  7. David Karr

    Jim Gibson Guest

    In article <>,
    David Karr <> wrote:

    > On Thursday, June 7, 2012 4:02:20 PM UTC-7, Ben Morrow wrote:


    > >
    > > This unlink probably wants to be outside the if. If (say) the internal
    > > zipfile is corrupted, and can't be read, you still need to clean up the
    > > tempfile.

    >
    > I was thinking about that, but I assume that it would fail if the file didn't
    > actually get created? I figured I would need some sort of exception handling
    > to do that cleanly (of course, if that was really important, I probably
    > should have already been doing that). I'm not very familiar with how Perl does exception handling.


    It generally just keeps going. unlink will return false and set $! to
    an error number and message. That is typical. You can ignore the error,
    as you have done.

    --
    Jim Gibson
    Jim Gibson, Jun 8, 2012
    #7
  8. On 08/06/12 16:55, David Karr wrote:
    > On Thursday, June 7, 2012 4:02:20 PM UTC-7, Ben Morrow wrote:
    >> Quoth David Karr<>:
    >>>
    >>> This is the key part of it:
    >>>
    >>> for my $archiveMember (@matchingArchiveList) {
    >>> #print "archiveMember[" . $archiveMember->fileName() . "]\n";
    >>> my $tempArchiveName = prepareTempFile();
    >>> #print "tempArchiveName[" . $tempArchiveName . "]\n";
    >>> $zip->extractMemberWithoutPaths($archiveMember, $tempArchiveName);
    >>> my $archiveZip = Archive::Zip->new();
    >>> my $archiveStatus = $archiveZip->read($tempArchiveName);
    >>> if ($archiveStatus == AZ_OK) {
    >>> processArchive($archiveZip, $entry, $zipName . ":" .
    >>> $archiveMember->fileName());
    >>> unlink($tempArchiveName);

    >>
    >> This unlink probably wants to be outside the if. If (say) the internal
    >> zipfile is corrupted, and can't be read, you still need to clean up the
    >> tempfile.

    >
    > I was thinking about that, but I assume that it would fail if the file didn't actually get created? I figured I would need some sort of exception handling to do that cleanly (of course, if that was really important, I probably should have already been doing that). I'm not very familiar with how Perl does exception handling.


    Here is an alternative implementation that uses IO::Uncompress::Unzip to
    walk a nested zip files to any depth. It just outputs the name of each
    member in all the zip files it finds as a proof of concept.

    No temp files needed.


    #!/usr/bin/perl

    use warnings;
    use strict;
    use IO::Uncompress::Unzip;

    sub walk
    {
    my $name = shift;
    my $fh = shift;
    my $length = shift;
    my $indent = shift ;

    my $unzip = new IO::Uncompress::Unzip $fh,
    InputLength => $length
    or die "Cannot open zip\n" ;

    my $status;
    for ($status = 1; $status > 0; $status = $unzip->nextStream())
    {

    my $name = $unzip->getHeaderInfo()->{Name};
    my $len = $unzip->getHeaderInfo()->{CompressedLength};
    $len = $len->get32bit() if ref $len eq 'U64';
    warn " " x $indent . "Processing member $name $len\n" ;

    if ($name =~ /.zip$/)
    {
    walk($name, $unzip, $len, $indent + 2);
    }
    else
    {
    # Deal with the payload if necessary
    # my $buff;
    # while (($status = $unzip->read($buff)) > 0) {
    # # Do something here
    # }
    }

    last if $status < 0;
    }

    die "Error processing $name: $!\n"
    if $status < 0 ;
    }

    my $file = shift;
    my $length = -s $file ;
    my $fh ;
    open $fh, "<$file" ;

    walk($file, $fh, $length, 0);
    Paul Marquess, Jun 9, 2012
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Graham Wood
    Replies:
    3
    Views:
    514
    A. Sinan Unur
    Jan 11, 2004
  2. Twig
    Replies:
    1
    Views:
    120
    A. Sinan Unur
    Jan 27, 2006
  3. MoshiachNow
    Replies:
    2
    Views:
    257
    Ilya Zakharevich
    Oct 4, 2006
  4. MoshiachNow

    Archive::Zip - zip file has "invalid" format

    MoshiachNow, Oct 5, 2006, in forum: Perl Misc
    Replies:
    1
    Views:
    152
  5. Bo Yang
    Replies:
    9
    Views:
    288
    -berlin.de
    Nov 20, 2006
Loading...

Share This Page