55from . import ffi
66from .ffi import (
77 ARCHIVE_EOF , OPEN_CALLBACK , READ_CALLBACK , CLOSE_CALLBACK , SEEK_CALLBACK ,
8- VOID_CB , page_size ,
8+ NO_OPEN_CB , NO_CLOSE_CB , page_size ,
99)
1010from .entry import ArchiveEntry , new_archive_entry
1111
@@ -57,15 +57,17 @@ def new_archive_read(format_name='all', filter_name='all', passphrase=None):
5757@contextmanager
5858def custom_reader (
5959 read_func , format_name = 'all' , filter_name = 'all' ,
60- open_func = VOID_CB , close_func = VOID_CB , block_size = page_size ,
61- archive_read_class = ArchiveRead , passphrase = None ,
60+ open_func = None , seek_func = None , close_func = None ,
61+ block_size = page_size , archive_read_class = ArchiveRead , passphrase = None ,
6262):
6363 """Read an archive using a custom function.
6464 """
65- open_cb = OPEN_CALLBACK (open_func )
65+ open_cb = OPEN_CALLBACK (open_func ) if open_func else NO_OPEN_CB
6666 read_cb = READ_CALLBACK (read_func )
67- close_cb = CLOSE_CALLBACK (close_func )
67+ close_cb = CLOSE_CALLBACK (close_func ) if close_func else NO_CLOSE_CB
6868 with new_archive_read (format_name , filter_name , passphrase ) as archive_p :
69+ if seek_func :
70+ ffi .read_set_seek_callback (archive_p , SEEK_CALLBACK (seek_func ))
6971 ffi .read_open (archive_p , None , open_cb , read_cb , close_cb )
7072 yield archive_read_class (archive_p )
7173
@@ -117,36 +119,9 @@ def stream_reader(
117119 """Read an archive from a stream.
118120
119121 The `stream` object must support the standard `readinto` method.
120- """
121- buf = create_string_buffer (block_size )
122- buf_p = cast (buf , c_void_p )
123122
124- def read_func (archive_p , context , ptrptr ):
125- # readinto the buffer, returns number of bytes read
126- length = stream .readinto (buf )
127- # write the address of the buffer into the pointer
128- ptrptr = cast (ptrptr , POINTER (c_void_p ))
129- ptrptr [0 ] = buf_p
130- # tell libarchive how much data was written into the buffer
131- return length
132-
133- open_cb = OPEN_CALLBACK (VOID_CB )
134- read_cb = READ_CALLBACK (read_func )
135- close_cb = CLOSE_CALLBACK (VOID_CB )
136- with new_archive_read (format_name , filter_name , passphrase ) as archive_p :
137- ffi .read_open (archive_p , None , open_cb , read_cb , close_cb )
138- yield ArchiveRead (archive_p )
139-
140-
141- @contextmanager
142- def seekable_stream_reader (
143- stream , format_name = 'all' , filter_name = 'all' , block_size = page_size ,
144- passphrase = None ,
145- ):
146- """Read an archive from a seekable stream.
147-
148- The `stream` object must support the standard `readinto`, 'seek' and
149- 'tell' methods.
123+ If `stream.seekable()` returns `True`, then an appropriate seek callback is
124+ passed to libarchive.
150125 """
151126 buf = create_string_buffer (block_size )
152127 buf_p = cast (buf , c_void_p )
@@ -165,11 +140,14 @@ def seek_func(archive_p, context, offset, whence):
165140 # tell libarchive the current position
166141 return stream .tell ()
167142
168- open_cb = OPEN_CALLBACK ( VOID_CB )
143+ open_cb = NO_OPEN_CB
169144 read_cb = READ_CALLBACK (read_func )
170- seek_cb = SEEK_CALLBACK (seek_func )
171- close_cb = CLOSE_CALLBACK (VOID_CB )
145+ close_cb = NO_CLOSE_CB
172146 with new_archive_read (format_name , filter_name , passphrase ) as archive_p :
173- ffi .read_set_seek_callback (archive_p , seek_cb )
147+ if stream .seekable ():
148+ ffi .read_set_seek_callback (archive_p , SEEK_CALLBACK (seek_func ))
174149 ffi .read_open (archive_p , None , open_cb , read_cb , close_cb )
175150 yield ArchiveRead (archive_p )
151+
152+
153+ seekable_stream_reader = stream_reader
0 commit comments