Pickwick has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,

in one of my applications I have a scalar with some zip data created using Archive::Zip in memory and I need to unzip it in another part of the application. Therefore I use IO::String with my already present scalar and gave that to Archive::Zip::Read. Everything seemed to work fine, the zip data got parsed without errors, I could fetch the members, their sizes etc., but whenever I wanted to access the contents of the members I got the following error:

IO error: seeking to local header

After some debugging in IO::String I found that seek fails because there's no more data attached, the following line evaluates to true and results 0 which leads to the error 4 returned from Archive::Zip.

my $buf = *$self->{buf} || return 0;

As data can't strangely loose itself I did some more debugging and seemed to find the root cause: read in Archive::Zip::Archive is closing the file handle it gets if it finished successfully, resulting in IO::String::close deleting the associated buffer. When I call another IO::String::open on my instance after read with the same zipped data as before, I'm successfully able to extract the contents of my buffers.

Does this look like a bug in Archive::Zip or am I doing something wrong? One reason to close the handle I can think of may be that read can't know if one is really interested in data and not only in some pieces of information about the members and reopening the handle in case of a file is easy. But there's nothing documented anywhere about this behavior and one needs to know about those things for cases like mine, where I want to use IO::String. Is there anything more compatible which I could use with zipped data already in memory?

From my point of view the proper behavior of read would be to only close the file handle if it created it on it's own, but not if it got one from the caller.

One thing I could imagine as workaorund is to subclass IO::String as something like IO::(Archive)ZipString and reimplement close to do nothing, but DESTROY to call close on the super class. This way read couldn't close the handle, but no memory leak would occur.

Thanks for your suggestions.

  • Comment on Using Archive::Zip reading from IO::String results in a seek error
  • Download Code

Replies are listed 'Best First'.
Re: Using Archive::Zip reading from IO::String results in a seek error
by Anonymous Monk on Aug 18, 2013 at 03:14 UTC

    Does this look like a bug in Archive::Zip or am I doing something wrong?

    Sounds like you're reusing an IO::String that has been closed

    Use  open my($fh), '<', \$string

    OTOH, IO::String has been obsolete since perl5.8

      Sounds like you're reusing an IO::String that has been closed

      Of course I do, that's what I already know and have written. ;-) The problem is that Archive::Zip::read is closing the handle and I would like to know if this is a bug or not. It looks like a bug to me, read should only close handles it opened itself.

Re: Using Archive::Zip reading from IO::String results in a seek error
by Pickwick (Beadle) on Aug 19, 2013 at 07:50 UTC