How to use phrase_from_stream with zipper_open_current?

Hi,

I’d like to open a ZIP file and process matching file entries using my DCG code with phrase_from_stream. The documentation for phrase_from_stream indicates the stream has to be bufferred. The zipper_open_current documentation doesn’t seem to specify a way for the stream to be bufferred (or what the “type” option does), and when I create a stream, the stream_property call indeed indicates that there is no bufferring.

?- zip_open("/home/sits/example.zip", read, Zipper, []), zipper_goto(Zipper, file("entry-in-zip.log")), zipper_open_current(Zipper, Stream, [encoding(utf8)]), phrase_from_stream(read_master_log_file, Stream).
ERROR: No permission to create lazy_list `<stream>(0x563b6c400890)'
ERROR: In:
ERROR:   [12] throw(error(permission_error(create,lazy_list,<stream>(0x563b6c400890)),_21576))
ERROR:   [10] pure_input:stream_to_lazy_list(<stream>(0x563b6c400890),_21616) at /usr/lib/swi-prolog/library/pure_input.pl:237
ERROR:    [9] pure_input:phrase_from_stream(user:read_master_log_file,<stream>(0x563b6c400890)) at /usr/lib/swi-prolog/library/pure_input.pl:134
ERROR:    [7] <user>
ERROR: 

Is there a way around this? I am hoping to avoid creating a temporary file on disk to process the file entry in the ZIP. Thanks.

1 Like

I can’t remeber the details as I did this several months ago but using SWI-Prolog binding to zlib was the key, in particular gzopen/N e.g.

    setup_call_cleanup(
        gzopen(ReferenceFile, read, ZIn, [type(binary)]),
        read_stream_to_codes(ZIn, Codes),
        close(ZIn)
    ),

My guess is that you should be able to replace read_stream_to_codes/2 with phrase_from_stream/2

HTH

1 Like

If you look at the source of phrase_from_stream/2, you see it raises this error if the stream is not buffered. You can use ?- edit(phrase_from_stream/2) to look at the source.

This is incorrect and pretty inefficient. Pushed a fix.

2 Likes

Thanks Jan… it looks good now.

Dear all,

I experience the same error with phrase_from_stream under docker with:
SWI-Prolog (threaded, 64 bits, version 8.3.18).

This is how I obtain the stream from a java web archive:

open_archive_entry(ArchiveFile, Entry, Stream) :-
    open(ArchiveFile, read, In, [type(binary)]),
    format(string(Info), 'Reading archive ~w: ~w', [ArchiveFile, Entry]),
    writeln(Info),
    archive_open(In, Archive, [close_parent(true)]),
    archive_next_header(Archive, Entry),
    archive_open_entry(Archive, Stream),
    archive_close(Archive).

Kind regards
Ronan Tanguy