Fixes #1675 - T1 eexec end finding spec compliance

The T1 spec (https://www-cdf.fnal.gov/offline/PostScript/T1_SPEC.PDF) on
page 14 says that:

> The text encrypted by eexec must be followed by 512 ASCII zeros. There may be
> white space characters (blank, tab, carriage return or line feed)
> interspersed among these zeros.

  * Add a failing test case with white space characters interspersed
    among the trailing zeros after the eexec

  * Fix eexec end finding so that it passes this new test case
This commit is contained in:
Bailey Parker 2019-07-31 23:46:50 -04:00
parent f9d12be58f
commit 6f4e44f13d
No known key found for this signature in database
GPG Key ID: B732B0333C7532C0
4 changed files with 83 additions and 3 deletions

5
.gitattributes vendored
View File

@ -4,3 +4,8 @@
# Explicitly declare text files you want to always be normalized and converted # Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout. # to native line endings on checkout.
*.py text *.py text
# Font files are binary (so that autocrlf doesn't muck with them)
*.lwfn binary
*.pfa binary
*.pfb binary

View File

@ -273,7 +273,9 @@ def writeOther(path, data, dohex=False):
# decryption tools # decryption tools
EEXECBEGIN = b"currentfile eexec" EEXECBEGIN = b"currentfile eexec"
EEXECEND = b'0' * 64 # The spec allows for 512 ASCII zeros interrupted by arbitrary whitespace to
# follow eexec
EEXECEND = re.compile(b'(0[ \t\r\n]*){512}', flags=re.M)
EEXECINTERNALEND = b"currentfile closefile" EEXECINTERNALEND = b"currentfile closefile"
EEXECBEGINMARKER = b"%-- eexec start\r" EEXECBEGINMARKER = b"%-- eexec start\r"
EEXECENDMARKER = b"%-- eexec end\r" EEXECENDMARKER = b"%-- eexec end\r"
@ -312,9 +314,10 @@ def findEncryptedChunks(data):
if eBegin < 0: if eBegin < 0:
break break
eBegin = eBegin + len(EEXECBEGIN) + 1 eBegin = eBegin + len(EEXECBEGIN) + 1
eEnd = data.find(EEXECEND, eBegin) endMatch = EEXECEND.search(data, eBegin)
if eEnd < 0: if not endMatch:
raise T1Error("can't find end of eexec part") raise T1Error("can't find end of eexec part")
eEnd = endMatch.start()
cypherText = data[eBegin:eEnd + 2] cypherText = data[eBegin:eEnd + 2]
if isHex(cypherText[:4]): if isHex(cypherText[:4]):
cypherText = deHexString(cypherText) cypherText = deHexString(cypherText)

View File

@ -0,0 +1,63 @@
%!FontType1-1.1: TestT1-Regular 1.0
%%BeginResource: font TestT1-Regular
12 dict dup begin
/FontType 1 def
/FontName /TestT1-Regular def
/FontInfo 14 dict dup begin
/version (1.0) def
/Notice (Test T1 is not a trademark of FontTools.) def
/Copyright (Copyright c 2015 by FontTools. No rights reserved.) def
/FullName (Test T1) def
/FamilyName (Test T1) def
/Weight (Regular) def
/ItalicAngle 0.000000 def
/isFixedPitch false def
/UnderlinePosition -75.000000 def
/UnderlineThickness 50.000000 def
/FSType 0 def
end def
/PaintType 0 def
/FontMatrix [0.001 0 0 0.001 0 0] def
/Encoding 256 array
0 1 255 {1 index exch /.notdef put} for
def
/FontBBox {50.000000 0.000000 668.000000 750.000000} def
end
currentfile eexec bab431ea06bb0a1031e1aa11919e714ac1ac5197cb08b39a4d7e746fca0af12d89ac0ebd1bc11ab1
b3887b922efcec739534242d2fd22e7c30e3edce24b93798627e1ac3387816a8c4b84d76047dada8
28b2ad27c5603046fecbc2a97adc5c37a68912324d2d435f2ee0ccc38df10ba1271a1c9af8897a6d
6e425cd7d18fd6bd64c2adadb74365bc101a850841669886291e158cbfa7f204b3fe0ba49ffe0c80
4f6795d32eb770c5fcd38a3879c06a4bb87b2d3ab100d8c2b5f89e9be99248575575025c66381446
e4d9183674880aef57fb2032a1e00431133b16f6d758de7c3d0c48a0fada1d40034742a69fb3a6f9
450d2251e659158a04697cbfa70907346d27d37ef683284385c44a1b5089bd29b4629b6483122dc8
cbce7327bdc33dd30e6fcdb346c0ddaf433a5ac740423aa35639b2386673832f5ae8cc380e9703ba
d3369533bfa85af9f56a090c9d97f5fc26ed102c07b647137e83632be51a65a532bd26430b59a31c
3cb037ded351c1d4e944733feb30a3e6f81c1a7b74ac4e0eadbe705412d47991c246e8820876bbc6
1f6a3e264ae6b2ad4b864b0d7abee289308bea26eb15d00d2b9103861386e0a5f1802ba06f916810
62110d2b1c3641806f78eea365614f440b580185e84bac6f87bee36108d95174c786600cf0e9dc4a
5545d1a84cfe8392115c0b7027c17fd460481d21f684af32204085690946327bfded992852645149
8d44150d2495bd2efe0db6a450c6e28d0a52ca234e252129d5095596b0d8de096682d2eb00bc8320
f257fd653b05a22eab7a193ccc315a6ee274a03ff1fdf443b310157a02656ca4b06c581dca8ced72
c6ddcab26eb856ad1093452c587438b7f8408c1311e19254955914612c09828fd4d4fc2b8b0406ea
2ee38348a8bdab88a77b8033366b2e469834c01b7bd73207b7c67756937c7a9232947fde2e0ea327
7b7d610e601b91389ccbcdd813c87db5333c0c723e48d3ef69285f246327978ce68ae9081076a227
1a962a2a10e2b1147ec40b0f6553a00c8b329118569d16fe04a4fa195caf1b04c52c9a562b72e0cd
e411d747af796b9d2fb086ed927efb0e5fc9f50aa18aaf4949cba0de0805210620a19eec4319dfef
a74d9d13d16f8ad793323a231347e6b40022a1100c1e064b8679c1da63a26dfb217a6037096ad796
320da5a9d0526eed51d7d64d3223e285c1a8c70780c59ecc9dd9bc90a0f84ffa038834918cebe247
f6e8fa4ca0654019196388f2df008e63bc32c8e5e686dbb69193b7749638c22b389fb1f090fbb007
fdb8a6ee4e4b29e123fe1652fe72239bd2c8
00000000000 00000000000000000000000000000000000000000000000000000
0000000000000000000000000000000 000000000000000000000000000000000
00000000000000000000000
00000000000000000000000000000000000000000
0000000000000000000000000000000000000000 000000000000000000000000
00
00000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000 00000000000
00000000000000000000 00000000000000000000000000000000000000000000
00000000000000000000
00000000000000000000000000000000000000000000
cleartomark
%%EndResource
%%EOF

View File

@ -14,6 +14,7 @@ DATADIR = os.path.join(CWD, 'data')
LWFN = os.path.join(DATADIR, 'TestT1-Regular.lwfn') LWFN = os.path.join(DATADIR, 'TestT1-Regular.lwfn')
PFA = os.path.join(DATADIR, 'TestT1-Regular.pfa') PFA = os.path.join(DATADIR, 'TestT1-Regular.pfa')
PFB = os.path.join(DATADIR, 'TestT1-Regular.pfb') PFB = os.path.join(DATADIR, 'TestT1-Regular.pfb')
WEIRD_ZEROS = os.path.join(DATADIR, 'TestT1-weird-zeros.pfa')
class FindEncryptedChunksTest(unittest.TestCase): class FindEncryptedChunksTest(unittest.TestCase):
@ -28,6 +29,14 @@ class FindEncryptedChunksTest(unittest.TestCase):
self.assertTrue(chunks[1][0]) self.assertTrue(chunks[1][0])
self.assertFalse(chunks[2][0]) self.assertFalse(chunks[2][0])
def test_findEncryptedChunks_weird_zeros(self):
with open(WEIRD_ZEROS, 'rb') as f:
data = f.read()
# Just assert that this doesn't raise any exception for not finding the
# end of eexec
t1Lib.findEncryptedChunks(data)
class DecryptType1Test(unittest.TestCase): class DecryptType1Test(unittest.TestCase):