Source code for invenio_previewer.extensions.zip
# -*- coding: utf-8 -*-
#
# This file is part of Invenio.
# Copyright (C) 2015-2019 CERN.
#
# Invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
"""Simple ZIP archive previewer."""
from __future__ import absolute_import, print_function
import os
import zipfile
import cchardet as chardet
from flask import current_app, render_template
from six import binary_type
from .._compat import text_type
from ..proxies import current_previewer
previewable_extensions = ['zip']
[docs]def make_tree(file):
"""Create tree structure from ZIP archive."""
max_files_count = current_app.config.get('PREVIEWER_ZIP_MAX_FILES', 1000)
tree = {'type': 'folder', 'id': -1, 'children': {}}
try:
with file.open() as fp:
zf = zipfile.ZipFile(fp)
# Detect filenames encoding.
sample = ' '.join(zf.namelist()[:max_files_count])
if not isinstance(sample, binary_type):
sample = sample.encode('utf-16be')
encoding = chardet.detect(sample).get('encoding', 'utf-8')
for i, info in enumerate(zf.infolist()):
if i > max_files_count:
raise BufferError('Too many files inside the ZIP file.')
comps = info.filename.split(os.sep)
node = tree
for c in comps:
if not isinstance(c, text_type):
c = c.decode(encoding)
if c not in node['children']:
if c == '':
node['type'] = 'folder'
continue
node['children'][c] = {
'name': c,
'type': 'item',
'id': 'item{0}'.format(i),
'children': {}
}
node = node['children'][c]
node['size'] = info.file_size
except BufferError:
return tree, True, None
except (zipfile.LargeZipFile):
return tree, False, 'Zipfile is too large to be previewed.'
except Exception as e:
current_app.logger.warning(str(e), exc_info=True)
return tree, False, 'Zipfile is not previewable.'
return tree, False, None
[docs]def children_to_list(node):
"""Organize children structure."""
if node['type'] == 'item' and len(node['children']) == 0:
del node['children']
else:
node['type'] = 'folder'
node['children'] = list(node['children'].values())
node['children'].sort(key=lambda x: x['name'])
node['children'] = map(children_to_list, node['children'])
return node
[docs]def can_preview(file):
"""Return True if filetype can be previewed."""
return file.is_local() and file.has_extensions('.zip')
[docs]def preview(file):
"""Return the appropriate template and pass the file and an embed flag."""
tree, limit_reached, error = make_tree(file)
list = children_to_list(tree)['children']
return render_template(
"invenio_previewer/zip.html",
file=file,
tree=list,
limit_reached=limit_reached,
error=error,
js_bundles=current_previewer.js_bundles + ['fullscreen_js.js'],
css_bundles=current_previewer.css_bundles,
)