[diffoscope] 01/01: Add comparator for Fontconfig cache files.
Chris Lamb
chris at chris-lamb.co.uk
Fri Jun 2 19:46:13 CEST 2017
This is an automated email from the git hooks/post-receive script.
lamby pushed a commit to branch experimental
in repository diffoscope.
commit df8360b1230c0c019cc8f0faa0f50cb5b1f7c265
Author: Chris Lamb <lamby at debian.org>
Date: Fri Jun 2 16:40:15 2017 +0100
Add comparator for Fontconfig cache files.
This was to diagnose issue #12567 in Tails [0].
[0] https://labs.riseup.net/code/issues/12567
Signed-off-by: Chris Lamb <lamby at debian.org>
---
diffoscope/comparators/__init__.py | 1 +
diffoscope/comparators/fontconfig.py | 91 +++++++++++++++++++++++++++++++++++
tests/comparators/test_fontconfig.py | 46 ++++++++++++++++++
tests/data/fontconfig_expected_diff | 18 +++++++
tests/data/test1-le64.cache-4 | Bin 0 -> 14208 bytes
tests/data/test2-le64.cache-4 | Bin 0 -> 15384 bytes
6 files changed, 156 insertions(+)
diff --git a/diffoscope/comparators/__init__.py b/diffoscope/comparators/__init__.py
index 38d9e58..d22aa79 100644
--- a/diffoscope/comparators/__init__.py
+++ b/diffoscope/comparators/__init__.py
@@ -52,6 +52,7 @@ class ComparatorManager(object):
('llvm.LlvmBitCodeFile',),
('sqlite.Sqlite3Database',),
('fonts.TtfFile',),
+ ('fontconfig.FontconfigCacheFile',),
('gettext.MoFile',),
('ipk.IpkFile',),
('rust.RustObjectFile',),
diff --git a/diffoscope/comparators/fontconfig.py b/diffoscope/comparators/fontconfig.py
new file mode 100644
index 0000000..dc2b981
--- /dev/null
+++ b/diffoscope/comparators/fontconfig.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+#
+# diffoscope: in-depth comparison of files, archives, and directories
+#
+# Copyright © 2017 Chris Lamb <lamby at debian.org>
+#
+# diffoscope is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# diffoscope is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with diffoscope. If not, see <https://www.gnu.org/licenses/>.
+
+import re
+import struct
+
+from diffoscope.difference import Difference
+
+from .utils.file import File
+from .utils.command import Command
+
+
+class FontconfigCacheFile(File):
+ MAGIC = struct.pack('<H', 0xFC04)
+ RE_FILE_EXTENSION = re.compile(r'\-le64\.cache-4$')
+
+ @staticmethod
+ def recognizes(file):
+ if not FontconfigCacheFile.RE_FILE_EXTENSION.search(file.name):
+ return False
+
+ with open(file.path, 'rb') as f:
+ return f.read(len(FontconfigCacheFile.MAGIC)) == \
+ FontconfigCacheFile.MAGIC
+
+ def compare_details(self, other, source=None):
+ return [Difference.from_text(
+ describe_cache_file(self.path),
+ describe_cache_file(other.path),
+ self.path,
+ other.path,
+ )]
+
+
+def describe_cache_file(filename):
+ fmt = '<IIQQQQQQQ'
+ fields = (
+ 'magic', 'version', 'size', 'dir', 'dirs', 'dirs_count', 'set',
+ 'checksum', 'checksum_nano',
+ )
+
+ with open(filename, 'rb') as f:
+ data = struct.unpack(fmt, f.read(struct.calcsize(fmt)))
+ kwargs = {x: y for x, y in zip(fields, data)}
+
+ kwargs['dir_name'] = read_null_terminated_string(f, kwargs['dir'])
+
+ return """
+struct FcCache {{
+ unsigned int magic = 0x{magic:08X}; /* FC_CACHE_MAGIC_MMAP or FC_CACHE_ALLOC */
+ int version = {version}; /* FC_CACHE_VERSION_NUMBER */
+ intptr_t size = {size}; /* size of file */
+ intptr_t dir = 0x{dir}; /* offset to dir name ("{dir_name}") */
+ intptr_t dirs = 0x{dirs:08X}; /* offset to subdirs */
+ int dirs_count = {dirs_count}; /* number of subdir strings */
+ intptr_t set = 0x{set:08X}; /* offset to font set */
+ int checksum = {checksum}; /* checksum of directory state */
+ int64_t checksum_nano = {checksum_nano}; /* checksum of directory state */
+}};
+""".format(**kwargs)
+
+
+def read_null_terminated_string(fileobj, offset=None):
+ result = ''
+
+ if offset is not None:
+ fileobj.seek(offset)
+
+ while True:
+ x = fileobj.read(1).decode('ascii')
+ if x in ('', '\0'):
+ break
+ result += x
+
+ return result
diff --git a/tests/comparators/test_fontconfig.py b/tests/comparators/test_fontconfig.py
new file mode 100644
index 0000000..229e69f
--- /dev/null
+++ b/tests/comparators/test_fontconfig.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+#
+# diffoscope: in-depth comparison of files, archives, and directories
+#
+# Copyright © 2017 Chris Lamb <lamby at debian.org>
+#
+# diffoscope is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# diffoscope is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with diffoscope. If not, see <https://www.gnu.org/licenses/>.
+
+import pytest
+
+from diffoscope.comparators.fontconfig import FontconfigCacheFile
+
+from ..utils.data import load_fixture, get_data
+
+cache1 = load_fixture('test1-le64.cache-4')
+cache2 = load_fixture('test2-le64.cache-4')
+
+
+def test_identification(cache1):
+ assert isinstance(cache1, FontconfigCacheFile)
+
+
+def test_no_differences(cache1):
+ difference = cache1.compare(cache1)
+ assert difference is None
+
+
+ at pytest.fixture
+def differences(cache1, cache2):
+ return cache1.compare(cache2).details
+
+
+def test_diff(differences):
+ expected_diff = get_data('fontconfig_expected_diff')
+ assert differences[0].unified_diff == expected_diff
diff --git a/tests/data/fontconfig_expected_diff b/tests/data/fontconfig_expected_diff
new file mode 100644
index 0000000..86001a3
--- /dev/null
+++ b/tests/data/fontconfig_expected_diff
@@ -0,0 +1,18 @@
+@@ -1,12 +1,12 @@
+
+ struct FcCache {
+ unsigned int magic = 0xFC02FC04; /* FC_CACHE_MAGIC_MMAP or FC_CACHE_ALLOC */
+ int version = 4; /* FC_CACHE_VERSION_NUMBER */
+- intptr_t size = 14208; /* size of file */
+- intptr_t dir = 0x56; /* offset to dir name ("/usr/share/fonts/type1/texlive-fonts-recommended") */
+- intptr_t dirs = 0x00000070; /* offset to subdirs */
++ intptr_t size = 15384; /* size of file */
++ intptr_t dir = 0x56; /* offset to dir name ("/usr/share/fonts/truetype/dejavu") */
++ intptr_t dirs = 0x00000060; /* offset to subdirs */
+ int dirs_count = 0; /* number of subdir strings */
+- intptr_t set = 0x00000070; /* offset to font set */
+- int checksum = 996; /* checksum of directory state */
++ intptr_t set = 0x00000060; /* offset to font set */
++ int checksum = 1496417874; /* checksum of directory state */
+ int64_t checksum_nano = 7018986666877744431; /* checksum of directory state */
+ };
diff --git a/tests/data/test1-le64.cache-4 b/tests/data/test1-le64.cache-4
new file mode 100644
index 0000000..1846dc4
Binary files /dev/null and b/tests/data/test1-le64.cache-4 differ
diff --git a/tests/data/test2-le64.cache-4 b/tests/data/test2-le64.cache-4
new file mode 100644
index 0000000..4ef0f15
Binary files /dev/null and b/tests/data/test2-le64.cache-4 differ
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/reproducible/diffoscope.git
More information about the diffoscope
mailing list