|
6 | 6 |
|
7 | 7 | from . import ffi |
8 | 8 | from .ffi import (ARCHIVE_EOF, OPEN_CALLBACK, READ_CALLBACK, CLOSE_CALLBACK, |
9 | | - VOID_CB, page_size) |
| 9 | + SEEK_CALLBACK, VOID_CB, page_size) |
10 | 10 | from .entry import ArchiveEntry, new_archive_entry |
11 | 11 |
|
12 | 12 |
|
@@ -120,3 +120,38 @@ def read_func(archive_p, context, ptrptr): |
120 | 120 | with new_archive_read(format_name, filter_name) as archive_p: |
121 | 121 | ffi.read_open(archive_p, None, open_cb, read_cb, close_cb) |
122 | 122 | yield ArchiveRead(archive_p) |
| 123 | + |
| 124 | + |
| 125 | +@contextmanager |
| 126 | +def seekable_stream_reader(stream, format_name='all', filter_name='all', |
| 127 | + block_size=page_size): |
| 128 | + """Read an archive from a seekable stream. |
| 129 | +
|
| 130 | + The `stream` object must support the standard `readinto`, 'seek' and |
| 131 | + 'tell' methods. |
| 132 | + """ |
| 133 | + buf = create_string_buffer(block_size) |
| 134 | + buf_p = cast(buf, c_void_p) |
| 135 | + |
| 136 | + def read_func(archive_p, context, ptrptr): |
| 137 | + # readinto the buffer, returns number of bytes read |
| 138 | + length = stream.readinto(buf) |
| 139 | + # write the address of the buffer into the pointer |
| 140 | + ptrptr = cast(ptrptr, POINTER(c_void_p)) |
| 141 | + ptrptr[0] = buf_p |
| 142 | + # tell libarchive how much data was written into the buffer |
| 143 | + return length |
| 144 | + |
| 145 | + def seek_func(archive_p, context, offset, whence): |
| 146 | + stream.seek(offset, whence) |
| 147 | + # tell libarchive the current position |
| 148 | + return stream.tell() |
| 149 | + |
| 150 | + open_cb = OPEN_CALLBACK(VOID_CB) |
| 151 | + read_cb = READ_CALLBACK(read_func) |
| 152 | + seek_cb = SEEK_CALLBACK(seek_func) |
| 153 | + close_cb = CLOSE_CALLBACK(VOID_CB) |
| 154 | + with new_archive_read(format_name, filter_name) as archive_p: |
| 155 | + ffi.read_set_seek_callback(archive_p, seek_cb) |
| 156 | + ffi.read_open(archive_p, None, open_cb, read_cb, close_cb) |
| 157 | + yield ArchiveRead(archive_p) |
0 commit comments