From 71d12a530955c7a2a8a4875a5545412a46b4c245 Mon Sep 17 00:00:00 2001 From: kumattau Date: Mon, 20 Dec 2021 09:14:48 +0900 Subject: [PATCH] Fix unexpected corruption check except for bundled fonts --- UPDATE.md | 6 +-- qtawesome/__init__.py | 92 ++++++++++++++++++++++++++++++---------- qtawesome/iconic_font.py | 29 ------------- setupbase.py | 32 +++++++------- 4 files changed, 88 insertions(+), 71 deletions(-) diff --git a/UPDATE.md b/UPDATE.md index 1741128e..f77e45a9 100644 --- a/UPDATE.md +++ b/UPDATE.md @@ -41,7 +41,7 @@ To update _Material Design Icons 6.x_, you must: - download ttf from - regenerate the json charmap with the `materialdesignicons.css` file from -The following script automatically download the last TTF font, generate the json charmap and display md5 hash of the TTF (to update iconic_font.py) +The following script automatically download the last TTF font, generate the json charmap and display md5 hash of the TTF (to update \_\_init__.py) ```Python import re @@ -95,7 +95,7 @@ To update _Phosphor_, you must: - download ttf from - regenerate the json charmap with the `phosphor.css` file from -The following script automatically download the last TTF font, generate the json charmap and display md5 hash of the TTF (to update iconic_font.py) +The following script automatically download the last TTF font, generate the json charmap and display md5 hash of the TTF (to update \_\_init__.py) ```Python import re @@ -148,7 +148,7 @@ To update _Remix Icon_, you must: - download ttf from - regenerate the json charmap with the `remixicon.css` file from -The following script automatically download the last TTF font, generate the json charmap and display md5 hash of the TTF (to update iconic_font.py) +The following script automatically download the last TTF font, generate the json charmap and display md5 hash of the TTF (to update \_\_init__.py) ```Python import re diff --git a/qtawesome/__init__.py b/qtawesome/__init__.py index 97259f46..562a0aa0 100644 --- a/qtawesome/__init__.py +++ b/qtawesome/__init__.py @@ -16,18 +16,70 @@ set_defaults """ +import hashlib +import os + # Third party imports from qtpy import QtCore, QtWidgets, QtGui # Local imports from ._version import __version__, version_info from .animation import Pulse, Spin -from .iconic_font import IconicFont, set_global_defaults +from .iconic_font import IconicFont, set_global_defaults, FontError +from .iconic_font import SYSTEM_FONTS as _SYSTEM_FONTS from .styles import dark, light # Constants _resource = { 'iconic': None } +_BUNDLED_FONTS = ( + ('fa', + 'fontawesome4.7-webfont.ttf', + 'fontawesome4.7-webfont-charmap.json'), + ('fa5', + 'fontawesome5-regular-webfont.ttf', + 'fontawesome5-regular-webfont-charmap.json'), + ('fa5s', + 'fontawesome5-solid-webfont.ttf', + 'fontawesome5-solid-webfont-charmap.json'), + ('fa5b', + 'fontawesome5-brands-webfont.ttf', + 'fontawesome5-brands-webfont-charmap.json'), + ('ei', + 'elusiveicons-webfont.ttf', + 'elusiveicons-webfont-charmap.json'), + ('mdi', + 'materialdesignicons5-webfont.ttf', + 'materialdesignicons5-webfont-charmap.json'), + ('mdi6', + 'materialdesignicons6-webfont.ttf', + 'materialdesignicons6-webfont-charmap.json'), + ('ph', + 'phosphor.ttf', + 'phosphor-charmap.json'), + ('ri', + 'remixicon.ttf', + 'remixicon-charmap.json'), + ('msc', + 'codicon.ttf', + 'codicon-charmap.json'), +) + + +# MD5 Hashes for font files bundled with qtawesome: +_MD5_HASHES = { + 'fontawesome4.7-webfont.ttf': 'b06871f281fee6b241d60582ae9369b9', + 'fontawesome5-regular-webfont.ttf': '808833867034fb67a4a86dd2155e195d', + 'fontawesome5-solid-webfont.ttf': '139654bb0acaba6b00ae30d5faf3d02f', + 'fontawesome5-brands-webfont.ttf': '085b1dd8427dbeff10bd55410915a3f6', + 'elusiveicons-webfont.ttf': '207966b04c032d5b873fd595a211582e', + 'materialdesignicons5-webfont.ttf': 'b7d40e7ef80c1d4af6d94902af66e524', + 'materialdesignicons6-webfont.ttf': '9a2f455e7cbce011368aee95d292613b', + 'phosphor.ttf': '5b8dc57388b2d86243566b996cc3a789', + 'remixicon.ttf': '888e61f04316f10bddfff7bee10c6dd0', + 'codicon.ttf': 'ca2f9e22cee3a59156b3eded74d87784', +} + def has_valid_font_ids(inst): """Validate instance's font ids are loaded to QFontDatabase. @@ -60,28 +112,22 @@ def _instance(): _resource['iconic'] = None if _resource['iconic'] is None: - _resource['iconic'] = IconicFont( - ('fa', - 'fontawesome4.7-webfont.ttf', - 'fontawesome4.7-webfont-charmap.json'), - ('fa5', - 'fontawesome5-regular-webfont.ttf', - 'fontawesome5-regular-webfont-charmap.json'), - ('fa5s', - 'fontawesome5-solid-webfont.ttf', - 'fontawesome5-solid-webfont-charmap.json'), - ('fa5b', - 'fontawesome5-brands-webfont.ttf', - 'fontawesome5-brands-webfont-charmap.json'), - ('ei', 'elusiveicons-webfont.ttf', 'elusiveicons-webfont-charmap.json'), - ('mdi', 'materialdesignicons5-webfont.ttf', - 'materialdesignicons5-webfont-charmap.json'), - ('mdi6', 'materialdesignicons6-webfont.ttf', - 'materialdesignicons6-webfont-charmap.json'), - ('ph', 'phosphor.ttf', 'phosphor-charmap.json'), - ('ri', 'remixicon.ttf', 'remixicon-charmap.json'), - ('msc', 'codicon.ttf', 'codicon-charmap.json'), - ) + # Verify that vendorized fonts are not corrupt + if not _SYSTEM_FONTS: + for fargs in _BUNDLED_FONTS: + ttf_filename = fargs[1] + ttf_hash = _MD5_HASHES.get(ttf_filename, None) + if ttf_hash is None: + continue + ttf_filepath = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "fonts", ttf_filename) + with open(ttf_filepath, "rb") as f: + ttf_calculated_hash_code = hashlib.md5(f.read()).hexdigest() + if ttf_calculated_hash_code != ttf_hash: + raise FontError(f"Font is corrupt at: '{ttf_filepath}'") + + _resource['iconic'] = IconicFont(*_BUNDLED_FONTS) return _resource['iconic'] diff --git a/qtawesome/iconic_font.py b/qtawesome/iconic_font.py index 72923874..3b846778 100644 --- a/qtawesome/iconic_font.py +++ b/qtawesome/iconic_font.py @@ -15,7 +15,6 @@ # Standard library imports from __future__ import print_function -import hashlib import json import os import warnings @@ -30,20 +29,6 @@ # use system fonts SYSTEM_FONTS = False -# MD5 Hashes for font files bundled with qtawesome: -MD5_HASHES = { - 'fontawesome4.7-webfont.ttf': 'b06871f281fee6b241d60582ae9369b9', - 'fontawesome5-regular-webfont.ttf': '808833867034fb67a4a86dd2155e195d', - 'fontawesome5-solid-webfont.ttf': '139654bb0acaba6b00ae30d5faf3d02f', - 'fontawesome5-brands-webfont.ttf': '085b1dd8427dbeff10bd55410915a3f6', - 'elusiveicons-webfont.ttf': '207966b04c032d5b873fd595a211582e', - 'materialdesignicons5-webfont.ttf': 'b7d40e7ef80c1d4af6d94902af66e524', - 'materialdesignicons6-webfont.ttf': '9a2f455e7cbce011368aee95d292613b', - 'phosphor.ttf': '5b8dc57388b2d86243566b996cc3a789', - 'remixicon.ttf': '888e61f04316f10bddfff7bee10c6dd0', - 'codicon.ttf': 'ca2f9e22cee3a59156b3eded74d87784', -} - def text_color(): try: @@ -303,20 +288,6 @@ def hook(obj): with open(os.path.join(directory, charmap_filename), 'r') as codes: self.charmap[prefix] = json.load(codes, object_hook=hook) - # Verify that vendorized fonts are not corrupt - if not SYSTEM_FONTS: - ttf_hash = MD5_HASHES.get(ttf_filename, None) - if ttf_hash is not None: - hasher = hashlib.md5() - with open(os.path.join(directory, ttf_filename), - 'rb') as f: - content = f.read() - hasher.update(content) - ttf_calculated_hash_code = hasher.hexdigest() - if ttf_calculated_hash_code != ttf_hash: - raise FontError(u"Font is corrupt at: '{0}'".format( - os.path.join(directory, ttf_filename))) - def icon(self, *names, **kwargs): """Return a QIcon object corresponding to the provided icon name.""" cache_key = '{}{}'.format(names,kwargs) diff --git a/setupbase.py b/setupbase.py index 08fe165c..7e989444 100644 --- a/setupbase.py +++ b/setupbase.py @@ -21,7 +21,7 @@ import distutils.log HERE = os.path.abspath(os.path.dirname(__file__)) -ICONIC_FONT_PY_PATH = os.path.join(HERE, 'qtawesome', 'iconic_font.py') +INIT_PY_PATH = os.path.join(HERE, 'qtawesome', '__init__.py') def rename_font(font_path, font_name): @@ -209,11 +209,11 @@ def run(self): # Store hashes for later: hashes[style] = hashlib.md5(data).hexdigest() - # Now it's time to patch "iconic_font.py": - iconic_path = ICONIC_FONT_PY_PATH - self.__print('Patching new MD5 hashes in: %s' % iconic_path) - with open(iconic_path, 'r') as iconic_file: - contents = iconic_file.read() + # Now it's time to patch "__init__.py": + init_path = INIT_PY_PATH + self.__print('Patching new MD5 hashes in: %s' % init_path) + with open(init_path, 'r') as init_file: + contents = init_file.read() # We read it in full, then use regex substitution: for style, md5 in hashes.items(): self.__print('New "%s" hash is: %s' % (style, md5)) @@ -221,9 +221,9 @@ def run(self): subst = r"\g<1>'" + md5 + "'" contents = re.sub(regex, subst, contents, 1) # and finally overwrite with the modified file: - self.__print('Dumping updated file: %s' % iconic_path) - with open(iconic_path, 'w') as iconic_file: - iconic_file.write(contents) + self.__print('Dumping updated file: %s' % init_path) + with open(init_path, 'w') as init_file: + init_file.write(contents) self.__print( '\nFinished!\n' @@ -295,16 +295,16 @@ def run(self): md5 = hashlib.md5(data).hexdigest() self.__print('New hash is: %s' % md5) - # Now it's time to patch "iconic_font.py": - self.__print('Patching new MD5 hashes in: %s' % ICONIC_FONT_PY_PATH) - with open(ICONIC_FONT_PY_PATH, 'r') as iconic_file: - contents = iconic_file.read() + # Now it's time to patch "__init__.py": + self.__print('Patching new MD5 hashes in: %s' % INIT_PY_PATH) + with open(INIT_PY_PATH, 'r') as init_file: + contents = init_file.read() regex = r"('codicon.ttf':\s+)'(\w+)'" subst = r"\g<1>'" + md5 + "'" contents = re.sub(regex, subst, contents, 1) - self.__print('Dumping updated file: %s' % ICONIC_FONT_PY_PATH) - with open(ICONIC_FONT_PY_PATH, 'w') as iconic_file: - iconic_file.write(contents) + self.__print('Dumping updated file: %s' % INIT_PY_PATH) + with open(INIT_PY_PATH, 'w') as init_file: + init_file.write(contents) self.__print( '\nFinished!\n'