Skip to content
Commits on Source (4)
......@@ -89,6 +89,7 @@ class ComparatorManager(object):
('docx.DocxFile',),
('zip.MozillaZipFile',),
('zip.ZipFile',),
('zip.JmodJavaModule',),
('image.JPEGImageFile',),
('image.ICOImageFile',),
('cbfs.CbfsFile',),
......
......@@ -160,19 +160,23 @@ class ZipContainer(Archive):
class ZipFile(File):
DESCRIPTION = 'ZIP archives'
CONTAINER_CLASS = ZipContainer
FILE_TYPE_RE = re.compile(
r'^(Zip archive|Java archive|EPUB document|OpenDocument (Text|Spreadsheet|Presentation|Drawing|Formula|Template|Text Template)|Google Chrome extension)\b'
)
ZIPINFO = Zipinfo
ZIPINFO_VERBOSE = ZipinfoVerbose
def compare_details(self, other, source=None):
differences = []
zipinfo_difference = None
if Config().exclude_directory_metadata != 'recursive':
zipinfo_difference = (
Difference.from_command(Zipinfo, self.path, other.path)
Difference.from_command(self.ZIPINFO, self.path, other.path)
or Difference.from_command(
ZipinfoVerbose, self.path, other.path
self.ZIPINFO_VERBOSE, self.path, other.path
)
or Difference.from_command(
BsdtarVerbose, self.path, other.path
......@@ -187,19 +191,25 @@ class ZipFile(File):
return differences
class MozillaZipCommandMixin(object):
class IgnoreReturncodeMixin(object):
@property
def returncode(self):
# zipinfo emits an error when reading Mozilla-optimized ZIPs,
# which is fine to ignore.
return 0
returncode = super().returncode
# zipinfo returns with an exit code of 1 or 2 when reading
# Mozilla-optimized or Java "jmod" ZIPs as they have non-standard
# headers which are safe to ignore.
if returncode in (1, 2):
returncode = 0
return returncode
class MozillaZipinfo(MozillaZipCommandMixin, Zipinfo):
class IgnoreReturncodeZipinfo(IgnoreReturncodeMixin, Zipinfo):
pass
class MozillaZipinfoVerbose(MozillaZipCommandMixin, ZipinfoVerbose):
class IgnoreReturncodeZipinfoVerbose(IgnoreReturncodeMixin, ZipinfoVerbose):
pass
......@@ -223,9 +233,13 @@ class MozillaZipContainer(ZipContainer):
return result
class MozillaZipFile(File):
class MozillaZipFile(ZipFile):
DESCRIPTION = 'Mozilla-optimized .ZIP archives'
CONTAINER_CLASS = MozillaZipContainer
ZIPINFO = IgnoreReturncodeZipinfo
ZIPINFO_VERBOSE = IgnoreReturncodeZipinfoVerbose
@classmethod
def recognizes(cls, file):
# Mozilla-optimized ZIPs start with a 32-bit little endian integer
......@@ -233,14 +247,10 @@ class MozillaZipFile(File):
# central directory (with a PK\x01\x02 signature)
return file.file_header[4:8] == b'PK\x01\x02'
def compare_details(self, other, source=None):
if Config().exclude_directory_metadata == 'recursive':
return []
zipinfo_difference = (
Difference.from_command(MozillaZipinfo, self.path, other.path)
or Difference.from_command(
MozillaZipinfoVerbose, self.path, other.path
)
or Difference.from_command(BsdtarVerbose, self.path, other.path)
)
return [zipinfo_difference]
class JmodJavaModule(ZipFile):
DESCRIPTION = 'Java .jmod modules'
FILE_TYPE_RE = re.compile(r'^Java jmod module\b')
ZIPINFO = IgnoreReturncodeZipinfo
ZIPINFO_VERBOSE = IgnoreReturncodeZipinfoVerbose
......@@ -19,7 +19,7 @@
import pytest
from diffoscope.comparators.zip import ZipFile, MozillaZipFile
from diffoscope.comparators.zip import ZipFile, MozillaZipFile, JmodJavaModule
from ..utils.data import load_fixture, get_data
from ..utils.tools import skip_unless_tools_exist
......@@ -33,6 +33,8 @@ encrypted_zip1 = load_fixture('encrypted1.zip')
encrypted_zip2 = load_fixture('encrypted2.zip')
mozzip1 = load_fixture('test1.mozzip')
mozzip2 = load_fixture('test2.mozzip')
jmod1 = load_fixture('test1.jmod')
jmod2 = load_fixture('test2.jmod')
test_comment1 = load_fixture('test_comment1.zip')
test_comment2 = load_fixture('test_comment2.zip')
......@@ -119,6 +121,27 @@ def test_mozzip_compare_non_existing(monkeypatch, mozzip1):
assert_non_existing(monkeypatch, mozzip1)
def test_jmod_identification(jmod1):
assert isinstance(jmod1, JmodJavaModule)
def test_jmod_no_differences(jmod1):
difference = jmod1.compare(jmod1)
assert difference is None
@pytest.fixture
def jmod_differences(jmod1, jmod2):
return jmod1.compare(jmod2).details
@skip_unless_tools_exist('zipinfo')
def test_jmod_metadata(jmod_differences, jmod1, jmod2):
expected_diff = get_data('jmod_zipinfo_expected_diff')
diff = jmod_differences[0].unified_diff
assert jmod_differences[0].unified_diff == expected_diff
def test_encrypted(encrypted_zip1, encrypted_zip2):
difference = encrypted_zip1.compare(encrypted_zip2)
assert difference is not None
......
@@ -1,8 +1,11 @@
-Zip file size: 9857 bytes, number of entries: 4
+Zip file size: 11672 bytes, number of entries: 7
warning [/dev/stdin]: 4 extra bytes at beginning or within zipfile
(attempting to process anyway)
--rw---- 2.0 fat 680 bl defN 19-Jul-17 04:54 classes/module-info.class
+-rw---- 2.0 fat 263 bl defN 19-Jul-17 04:54 classes/module-info.class
+-rw---- 2.0 fat 292 bl defN 19-Jul-17 04:54 classes/javax/transaction/xa/Xid.class
+-rw---- 2.0 fat 1062 bl defN 19-Jul-17 04:54 classes/javax/transaction/xa/XAResource.class
+-rw---- 2.0 fat 1497 bl defN 19-Jul-17 04:54 classes/javax/transaction/xa/XAException.class
-rw---- 2.0 fat 2114 bl defN 19-Jul-17 04:54 legal/ADDITIONAL_LICENSE_INFO
-rw---- 2.0 fat 1522 bl defN 19-Jul-17 04:54 legal/ASSEMBLY_EXCEPTION
-rw---- 2.0 fat 19274 bl defN 19-Jul-17 04:54 legal/LICENSE
-4 files, 23590 bytes uncompressed, 9281 bytes compressed: 60.7%
+7 files, 26024 bytes uncompressed, 10562 bytes compressed: 59.4%