1
1
#!/usr/bin/env python3
2
2
# -*- coding: utf-8 -*-
3
3
4
- #----------------------------------------------------------------
4
+ #------------------------------------------------------------------------------------------------------
5
5
# checksum.py
6
6
# A SHA1 hash checksum list generator for fonts and fontTools
7
- # XML dumps of font OpenType table data
7
+ # XML dumps of font OpenType table data + checksum testing
8
+ # script
8
9
#
9
10
# Copyright 2018 Christopher Simpkins
10
11
# MIT License
11
12
#
13
+ # Dependencies: Python fontTools library
14
+ #
12
15
# Usage: checksum.py (options) [file path 1]...[file path n]
13
16
#
14
- # Dependencies: Python fontTools library
15
- #----------------------------------------------------------------
17
+ # Options:
18
+ # -h, --help Help
19
+ # -t, --ttx Calculate SHA1 hash values from ttx dump of XML (default = font binary)
20
+ # -s, --stdout Stream to standard output stream (default = write to disk as 'checksum.txt')
21
+ # -c, --check Test SHA1 checksum values against a valid checksum file
22
+ #
23
+ # Options, --ttx only:
24
+ # -e, --exclude Excluded OpenType table (may be used more than once, mutually exclusive with -i)
25
+ # -i, --include Included OpenType table (may be used more than once, mutually exclusive with -e)
26
+ # -n, --noclean Do not discard .ttx files that are used to calculate SHA1 hashes
27
+ #-------------------------------------------------------------------------------------------------------
16
28
17
29
import argparse
18
30
import hashlib
24
36
from fontTools .ttLib import TTFont
25
37
26
38
27
- def main (filepaths , stdout_write = False , use_ttx = False , include_tables = None , exclude_tables = None , do_not_cleanup = False ):
39
+ def write_checksum (filepaths , stdout_write = False , use_ttx = False , include_tables = None , exclude_tables = None , do_not_cleanup = False ):
28
40
checksum_dict = {}
29
41
for path in filepaths :
30
42
if not os .path .exists (path ):
@@ -42,6 +54,8 @@ def main(filepaths, stdout_write=False, use_ttx=False, include_tables=None, excl
42
54
temp_ttx_path = path + ".ttx"
43
55
44
56
tt = TTFont (path )
57
+ # important to keep the newlinestr value defined here as hash values will change across platforms
58
+ # if platform specific newline values are assumed
45
59
tt .saveXML (temp_ttx_path , newlinestr = "\n " , skipTables = exclude_tables , tables = include_tables )
46
60
checksum_path = temp_ttx_path
47
61
else :
@@ -55,7 +69,7 @@ def main(filepaths, stdout_write=False, use_ttx=False, include_tables=None, excl
55
69
sys .exit (1 )
56
70
checksum_path = path
57
71
58
- file_contents = read_binary (checksum_path )
72
+ file_contents = _read_binary (checksum_path )
59
73
60
74
# store SHA1 hash data and associated file path basename in the checksum_dict dictionary
61
75
checksum_dict [basename (checksum_path )] = hashlib .sha1 (file_contents ).hexdigest ()
@@ -78,7 +92,48 @@ def main(filepaths, stdout_write=False, use_ttx=False, include_tables=None, excl
78
92
file .write (checksum_out_data )
79
93
80
94
81
- def read_binary (filepath ):
95
+ def check_checksum (filepaths ):
96
+ check_failed = False
97
+ for path in filepaths :
98
+ if not os .path .exists (path ):
99
+ sys .stderr .write ("[checksum.py] ERROR: " + filepath + " is not a valid filepath" + os .linesep )
100
+ sys .exit (1 )
101
+
102
+ with open (path , mode = 'r' ) as file :
103
+ for line in file .readlines ():
104
+ cleaned_line = line .rstrip ()
105
+ line_list = cleaned_line .split (" " )
106
+ # eliminate empty strings parsed from > 1 space characters
107
+ line_list = list (filter (None , line_list ))
108
+ if len (line_list ) == 2 :
109
+ expected_sha1 = line_list [0 ]
110
+ test_path = line_list [1 ]
111
+ else :
112
+ sys .stderr .write ("[checksum.py] ERROR: failed to parse checksum file values" + os .linesep )
113
+ sys .exit (1 )
114
+
115
+ if not os .path .exists (test_path ):
116
+ print (test_path + ": Filepath is not valid, ignored" )
117
+ else :
118
+ file_contents = _read_binary (test_path )
119
+ observed_sha1 = hashlib .sha1 (file_contents ).hexdigest ()
120
+ if observed_sha1 == expected_sha1 :
121
+ print (test_path + ": OK" )
122
+ else :
123
+ print ("-" * 80 )
124
+ print (test_path + ": === FAIL ===" )
125
+ print ("Expected vs. Observed:" )
126
+ print (expected_sha1 )
127
+ print (observed_sha1 )
128
+ print ("-" * 80 )
129
+ check_failed = True
130
+
131
+ # exit with status code 1 if any fails detected across all tests in the check
132
+ if check_failed is True :
133
+ sys .exit (1 )
134
+
135
+
136
+ def _read_binary (filepath ):
82
137
with open (filepath , mode = 'rb' ) as file :
83
138
return file .read ()
84
139
@@ -88,11 +143,15 @@ def read_binary(filepath):
88
143
parser .add_argument ("-t" , "--ttx" , help = "Calculate from ttx file" , action = "store_true" )
89
144
parser .add_argument ("-s" , "--stdout" , help = "Write output to stdout stream" , action = "store_true" )
90
145
parser .add_argument ("-n" , "--noclean" , help = "Do not discard *.ttx files used to calculate SHA1 hashes" , action = "store_true" )
146
+ parser .add_argument ("-c" , "--check" , help = "Verify checksum values vs. files" , action = "store_true" )
91
147
parser .add_argument ("filepaths" , nargs = "+" , help = "One or more file paths to font binary files" )
92
148
93
149
parser .add_argument ("-i" , "--include" , action = "append" , help = "Included OpenType tables for ttx data dump" )
94
150
parser .add_argument ("-e" , "--exclude" , action = "append" , help = "Excluded OpenType tables for ttx data dump" )
95
151
96
152
args = parser .parse_args (sys .argv [1 :])
97
153
98
- main (args .filepaths , stdout_write = args .stdout , use_ttx = args .ttx , do_not_cleanup = args .noclean , include_tables = args .include , exclude_tables = args .exclude )
154
+ if args .check is True :
155
+ check_checksum (args .filepaths )
156
+ else :
157
+ write_checksum (args .filepaths , stdout_write = args .stdout , use_ttx = args .ttx , do_not_cleanup = args .noclean , include_tables = args .include , exclude_tables = args .exclude )
0 commit comments