%PDF- %PDF-
| Direktori : /lib/calibre/calibre/utils/ |
| Current File : //lib/calibre/calibre/utils/seven_zip.py |
#!/usr/bin/env python3
# License: GPL v3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
import os
import re
from calibre.constants import iswindows
def open_archive(path_or_stream, mode='r'):
from py7zr import SevenZipFile
return SevenZipFile(path_or_stream, mode=mode)
def names(path_or_stream):
with open_archive(path_or_stream) as zf:
return tuple(zf.getnames())
def extract_member(path_or_stream, match=None, name=None):
if iswindows and name is not None:
name = name.replace(os.sep, '/')
if match is None:
match = re.compile(r'\.(jpg|jpeg|gif|png)\s*$', re.I)
def is_match(fname):
if iswindows:
fname = fname.replace(os.sep, '/')
return (name is not None and fname == name) or \
(match is not None and match.search(fname) is not None)
with open_archive(path_or_stream) as ar:
all_names = list(filter(is_match, ar.getnames()))
if all_names:
return all_names[0] , ar.read(all_names[:1])[all_names[0]].read()
def extract_cover_image(stream):
pos = stream.tell()
from calibre.libunzip import name_ok, sort_key
all_names = sorted(names(stream), key=sort_key)
stream.seek(pos)
for name in all_names:
if name_ok(name):
return extract_member(stream, name=name, match=None)
def extract(path_or_stream, location):
with open_archive(path_or_stream) as f:
f.extract(location)
# Test {{{
def test_basic():
from tempfile import TemporaryDirectory
from calibre import CurrentDir
tdata = {
'1/sub-one': b'sub-one\n',
'2/sub-two.txt': b'sub-two\n',
'F\xfc\xdfe.txt': b'unicode\n',
'max-compressed': b'max\n',
'one.txt': b'one\n',
'symlink': b'2/sub-two.txt',
'uncompressed': b'uncompressed\n',
'\u8bf6\u6bd4\u5c41.txt': b'chinese unicode\n'}
def do_test():
for name, data in tdata.items():
if '/' in name:
os.makedirs(os.path.dirname(name), exist_ok=True)
with open(name, 'wb') as f:
f.write(data)
with open_archive(os.path.join('a.7z'), mode='w') as zf:
for name in tdata:
zf.write(name)
with open_archive(os.path.join('a.7z')) as zf:
if set(zf.getnames()) != set(tdata):
raise ValueError('names not equal')
read_data = {name:af.read() for name, af in zf.readall().items()}
if read_data != tdata:
raise ValueError('data not equal')
for name in tdata:
if name not in '1 2 symlink'.split():
with open(os.path.join(tdir, name), 'rb') as s:
if s.read() != tdata[name]:
raise ValueError('Did not extract %s properly' % name)
with TemporaryDirectory('test-7z') as tdir, CurrentDir(tdir):
do_test()
if __name__ == '__main__':
test_basic()