diff --git a/Lib/woffTools/__init__.py b/Lib/woffTools/__init__.py index 930f30f..31f757f 100644 --- a/Lib/woffTools/__init__.py +++ b/Lib/woffTools/__init__.py @@ -7,16 +7,30 @@ Those objects are much faster than WOFFFont, but they require much more care. """ +from __future__ import print_function +from future import standard_library +standard_library.install_aliases() +import six +from builtins import range +from builtins import object import zlib import struct -from fontTools.misc import sstruct -from cStringIO import StringIO +from io import BytesIO from xml.etree import ElementTree from fontTools.ttLib import TTFont, debugmsg, sortedTagList -from fontTools.ttLib.sfnt import getSearchRange, calcChecksum, SFNTDirectoryEntry, \ +from fontTools.ttLib.sfnt import calcChecksum, SFNTDirectoryEntry, \ sfntDirectoryFormat, sfntDirectorySize, sfntDirectoryEntryFormat, sfntDirectoryEntrySize +try: + from fontTools.ttLib.sfnt import getSearchRange +except ImportError: + from fontTools.ttLib import getSearchRange + +try: + from fontTools.misc.sstruct import sstruct +except ImportError: + from fontTools.misc import sstruct # ----------- # Main Object @@ -60,6 +74,7 @@ def __init__(self, file=None, flavor="\000\001\000\000", self.minorVersion = 0 self._metadata = None self._tableOrder = None + self._tableCache=None if file is not None: if not hasattr(file, "read"): @@ -68,13 +83,13 @@ def __init__(self, file=None, flavor="\000\001\000\000", self.flavor = self.reader.flavor self.majorVersion = self.reader.majorVersion self.minorVersion = self.reader.minorVersion - self._tableOrder = self.reader.keys() + self._tableOrder = list(self.reader.keys()) else: self._metadata = ElementTree.Element("metadata", version="1.0") self.privateData = None def __getattr__(self, attr): - if attr not in ("privateData", "metadata"): + if attr not in ("privateData", "metadata", "lazy"): raise AttributeError(attr) # metadata if attr == "metadata": @@ -91,12 +106,18 @@ def __getattr__(self, attr): return None # private data elif attr == "privateData": - if not hasattr(self, "privateData"): - privateData = None - if self.reader is not None: - privateData = self.reader.privateData - self.privateData = privateData - return self.privateData + # ToDo: In Python 3 hasattr makes a infinite recursion here. Skipping support for privateData in Python 3 for now + if six.PY2: + if not hasattr(self, "privateData"): + privateData = None + if self.reader is not None: + privateData = self.reader.privateData + self.privateData = privateData + return self.privateData + else: + return None + elif attr == "lazy": + return False # fallback to None return None @@ -155,7 +176,7 @@ def save(self, file, compressionLevel=9, recompressTables=False, reorderTables=T # if DSIG is to be written, the table order # must be completely specified. otherwise the # DSIG may not be valid after decoding the WOFF. - tags = self.keys() + tags = list(self.keys()) if "GlyphOrder" in tags: tags.remove("GlyphOrder") if "DSIG" in tags: @@ -206,7 +227,7 @@ def save(self, file, compressionLevel=9, recompressTables=False, reorderTables=T if hasattr(self, "metadata"): declaration = "\n" tree = ElementTree.ElementTree(self.metadata) - f = StringIO() + f = BytesIO() tree.write(f, encoding="utf-8") metadata = f.getvalue() # make sure the metadata starts with the declaration @@ -294,7 +315,7 @@ def keys(self): of each table. """ sorter = [] - for tag, entry in self.tables.items(): + for tag, entry in list(self.tables.items()): sorter.append((entry.offset, tag)) order = [tag for offset, tag in sorted(sorter)] return order @@ -314,8 +335,8 @@ def __getitem__(self, tag): if self.checkChecksums > 1: assert checksum == entry.origChecksum, "bad checksum for '%s' table" % tag elif checksum != entry.origChecksum: - print "bad checksum for '%s' table" % tag - print + print("bad checksum for '%s' table" % tag) + print() return data def getCompressedTableData(self, tag): @@ -683,7 +704,7 @@ def calcHeadCheckSumAdjustment(flavor, tables): sfntEntry.length = entry["length"] directory += sfntEntry.toString() # calculate the checkSumAdjustment - checkSums = [entry["checkSum"] for entry in tables.values()] + checkSums = [entry["checkSum"] for entry in list(tables.values())] checkSums.append(calcChecksum(directory)) checkSumAdjustment = sum(checkSums) checkSumAdjustment = (0xB1B0AFBA - checkSumAdjustment) & 0xffffffff @@ -913,8 +934,8 @@ def _testOverlaps(tableDirectory): edges[entry["tag"]] = (start, end) # look for overlaps overlaps = set() - for tag, (start, end) in edges.items(): - for otherTag, (otherStart, otherEnd) in edges.items(): + for tag, (start, end) in list(edges.items()): + for otherTag, (otherStart, otherEnd) in list(edges.items()): tag = tag.strip() otherTag = otherTag.strip() if tag == otherTag: diff --git a/Lib/woffTools/test/test_validate.py b/Lib/woffTools/test/test_validate.py index 71a05b6..c83bf41 100644 --- a/Lib/woffTools/test/test_validate.py +++ b/Lib/woffTools/test/test_validate.py @@ -696,7 +696,7 @@ def decompressedLengthTest1(): header, directory, tableData = defaultTestData(header=True, directory=True, tableData=True) origData = testDataTableData compData = zlib.compress(origData) - for tag, (origData, compData) in tableData.items(): + for tag, (origData, compData) in list(tableData.items()): tableData[tag] = (origData, zlib.compress(origData)) updateDirectoryEntries(directory, tableData) return packTestHeader(header) + packTestDirectory(directory) + packTestTableData(directory, tableData) @@ -711,7 +711,7 @@ def decompressedLengthTest2(): header, directory, tableData = defaultTestData(header=True, directory=True, tableData=True) origData = testDataTableData compData = zlib.compress(origData) - for tag, (origData, compData) in tableData.items(): + for tag, (origData, compData) in list(tableData.items()): tableData[tag] = (origData, zlib.compress(origData)) updateDirectoryEntries(directory, tableData) for entry in directory: @@ -952,7 +952,7 @@ def decompressionTest1(): (False, 'PASS') """ header, directory, tableData = defaultTestData(header=True, directory=True, tableData=True) - for tag, (origData, compData) in tableData.items(): + for tag, (origData, compData) in list(tableData.items()): tableData[tag] = (origData, zlib.compress(compData)) updateDirectoryEntries(directory, tableData) return packTestHeader(header) + packTestDirectory(directory) + packTestTableData(directory, tableData) @@ -965,7 +965,7 @@ def decompressionTest2(): (True, 'ERROR') """ header, directory, tableData = defaultTestData(header=True, directory=True, tableData=True) - for tag, (origData, compData) in tableData.items(): + for tag, (origData, compData) in list(tableData.items()): compData = "".join(reversed(zlib.compress(compData))) tableData[tag] = (origData, compData) updateDirectoryEntries(directory, tableData) diff --git a/Lib/woffTools/tools/css.py b/Lib/woffTools/tools/css.py index 00298a9..541d1ff 100644 --- a/Lib/woffTools/tools/css.py +++ b/Lib/woffTools/tools/css.py @@ -5,9 +5,13 @@ This can also be used as a command line tool for generating CSS @font-face rules from WOFF files. """ +from __future__ import print_function # import test +from future import standard_library +standard_library.install_aliases() +from builtins import hex importErrors = [] try: import numpy @@ -24,13 +28,13 @@ if importErrors: import sys - print "Could not import needed module(s):", ", ".join(importErrors) + print("Could not import needed module(s):", ", ".join(importErrors)) sys.exit() # import import os -import urllib +import urllib.request, urllib.parse, urllib.error import optparse from woffTools import WOFFFont from woffTools.tools.support import findUniqueFileName @@ -90,7 +94,7 @@ def makeFontFaceSrc(font, fileName, doLocalSrc=True): s = "/* " + s + " */" sources.append(s) # file name - s = "url(\"%s\")" % urllib.quote(fileName) # XXX: format(\"woff\") + s = "url(\"%s\")" % urllib.parse.quote(fileName) # XXX: format(\"woff\") sources.append(s) # write sources = "\n\t".join(sources) @@ -194,7 +198,7 @@ def _skimNameIDs(font, priority): text = nameRecord.string nameIDs[nameID, platformID, platEncID, langID] = text for (nameID, platformID, platEncID, langID) in priority: - for (nID, pID, pEID, lID), text in nameIDs.items(): + for (nID, pID, pEID, lID), text in list(nameIDs.items()): if nID != nameID: continue if pID != platformID and platformID is not None: @@ -203,6 +207,7 @@ def _skimNameIDs(font, priority): continue if lID != langID and langID is not None: continue + text = text.decode("utf-8") text = "".join([i for i in text if i != "\x00"]) return text @@ -252,22 +257,23 @@ def makeFontFaceRule(font, fontPath, doLocalSrc=True): """ def main(): - parser = optparse.OptionParser(usage=usage, description=description, version="%prog 0.1beta") + parser = optparse.OptionParser(usage=usage, description=description, version="%prog 0.2") parser.add_option("-d", dest="outputDirectory", help="Output directory. The default is to output the CSS into the same directory as the font file.") parser.add_option("-o", dest="outputFileName", help="Output file name. The default is \"fontfilename.css\". If this file already exists a time stamp will be added to the file name.") parser.add_option("-l", action="store_true", dest="doLocalSrc", help="Write \"local\" instructions as part of the \"src\" descriptor.") (options, args) = parser.parse_args() outputDirectory = options.outputDirectory if outputDirectory is not None and not os.path.exists(outputDirectory): - print "Directory does not exist:", outputDirectory + print("Directory does not exist:", outputDirectory) sys.exit() for fontPath in args: if not os.path.exists(fontPath): - print "File does not exist:", fontPath + print("File does not exist:", fontPath) sys.exit() else: - print "Creating CSS: %s..." % fontPath - fontPath = fontPath.decode("utf-8") + print("Creating CSS: %s..." % fontPath) + if hasattr(fontPath, "decode"): + fontPath = fontPath.decode("utf-8") font = WOFFFont(fontPath) css = makeFontFaceRule(font, fontPath, doLocalSrc=options.doLocalSrc) # make the output file name @@ -285,7 +291,7 @@ def main(): path = os.path.join(directory, fileName) path = findUniqueFileName(path) f = open(path, "wb") - f.write(css) + f.write(css.encode('utf-8')) f.close() if __name__ == "__main__": diff --git a/Lib/woffTools/tools/info.py b/Lib/woffTools/tools/info.py index 26253c3..595301e 100644 --- a/Lib/woffTools/tools/info.py +++ b/Lib/woffTools/tools/info.py @@ -4,9 +4,14 @@ This can also be used as a command line tool. """ +from __future__ import print_function # import test +from builtins import str +from builtins import hex +from builtins import chr +from builtins import range importErrors = [] try: import numpy @@ -23,7 +28,7 @@ if importErrors: import sys - print "Could not import needed module(s):", ", ".join(importErrors) + print("Could not import needed module(s):", ", ".join(importErrors)) sys.exit() # import @@ -175,7 +180,7 @@ def writePrivateData(font, writer): src = font.privateData length = 16 result = [] - for i in xrange(0, len(src), length): + for i in range(0, len(src), length): s = src[i:i+length] hexa = [] c = [] @@ -256,22 +261,23 @@ def reportInfo(font, fontPath): """ def main(): - parser = optparse.OptionParser(usage=usage, description=description, version="%prog 0.1beta") + parser = optparse.OptionParser(usage=usage, description=description, version="%prog 0.2") parser.add_option("-d", dest="outputDirectory", help="Output directory. The default is to output the report into the same directory as the font file.") parser.add_option("-o", dest="outputFileName", help="Output file name. The default is \"fontfilename_info.html\".") parser.set_defaults(excludeTests=[]) (options, args) = parser.parse_args() outputDirectory = options.outputDirectory if outputDirectory is not None and not os.path.exists(outputDirectory): - print "Directory does not exist:", outputDirectory + print("Directory does not exist:", outputDirectory) sys.exit() for fontPath in args: if not os.path.exists(fontPath): - print "File does not exist:", fontPath + print("File does not exist:", fontPath) sys.exit() else: - print "Creating Info Report: %s..." % fontPath - fontPath = fontPath.decode("utf-8") + print("Creating Info Report: %s..." % fontPath) + if hasattr(fontPath, 'decode'): + fontPath = fontPath.decode("utf-8") font = WOFFFont(fontPath) html = reportInfo(font, fontPath) # make the output file name @@ -289,7 +295,7 @@ def main(): path = os.path.join(directory, fileName) path = findUniqueFileName(path) f = open(path, "wb") - f.write(html) + f.write(html.encode('utf-8')) f.close() if __name__ == "__main__": diff --git a/Lib/woffTools/tools/proof.py b/Lib/woffTools/tools/proof.py index 6bf4055..352cf0f 100644 --- a/Lib/woffTools/tools/proof.py +++ b/Lib/woffTools/tools/proof.py @@ -5,9 +5,11 @@ This can also be used as a command line tool for generating proofs from WOFF files. """ +from __future__ import print_function # import test +from builtins import chr importErrors = [] try: import numpy @@ -24,7 +26,7 @@ if importErrors: import sys - print "Could not import needed module(s):", ", ".join(importErrors) + print("Could not import needed module(s):", ", ".join(importErrors)) sys.exit() # import @@ -103,7 +105,7 @@ def makeCharacterSet(font): categorizedCharacters = {} glyphNameToCharacter = {} for value, glyphName in sorted(mapping.items()): - character = unichr(value) + character = chr(value) # skip whitespace if not character.strip(): continue @@ -161,7 +163,7 @@ def proofFont(font, fontPath, sampleText=None): defaultSampleText = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. The quick brown fox jumps over the lazy dog." def main(): - parser = optparse.OptionParser(usage=usage, description=description, version="%prog 0.1beta") + parser = optparse.OptionParser(usage=usage, description=description, version="%prog 0.2") parser.add_option("-d", dest="outputDirectory", help="Output directory. The default is to output the proof into the same directory as the font file.") parser.add_option("-o", dest="outputFileName", help="Output file name. The default is \"fontfilename_proof.html\".") parser.add_option("-t", dest="sampleTextFile", help="Sample text file. A file containing sample text to display. If not file is provided, The quick brown fox... will be used.") @@ -169,23 +171,24 @@ def main(): (options, args) = parser.parse_args() outputDirectory = options.outputDirectory if outputDirectory is not None and not os.path.exists(outputDirectory): - print "Directory does not exist:", outputDirectory + print("Directory does not exist:", outputDirectory) sys.exit() sampleText = defaultSampleText if options.sampleTextFile: if not os.path.exists(options.sampleTextFile): - print "Sample text file does not exist:", options.sampleTextFile + print("Sample text file does not exist:", options.sampleTextFile) sys.exit() f = open(options.sampleTextFile, "r") sampleText = f.read() f.close() for fontPath in args: if not os.path.exists(fontPath): - print "File does not exist:", fontPath + print("File does not exist:", fontPath) sys.exit() else: - print "Creating Proof: %s..." % fontPath - fontPath = fontPath.decode("utf-8") + print("Creating Proof: %s..." % fontPath) + if hasattr(fontPath, "decode"): + fontPath = fontPath.decode("utf-8") font = WOFFFont(fontPath) html = proofFont(font, fontPath, sampleText=sampleText) # make the output file name @@ -203,7 +206,7 @@ def main(): path = os.path.join(directory, fileName) path = findUniqueFileName(path) f = open(path, "wb") - f.write(html) + f.write(html.encode('utf-8')) f.close() if __name__ == "__main__": diff --git a/Lib/woffTools/tools/support.py b/Lib/woffTools/tools/support.py index b3a207f..0b6d017 100644 --- a/Lib/woffTools/tools/support.py +++ b/Lib/woffTools/tools/support.py @@ -1,7 +1,10 @@ +from future import standard_library +standard_library.install_aliases() +from builtins import object import os import time from xml.etree import ElementTree -from cStringIO import StringIO +from io import BytesIO # ---------------------- # Very Simple XML Writer @@ -36,7 +39,7 @@ def write(self, text): self._elements[-1].text += text def compile(self, encoding="utf-8"): - f = StringIO() + f = BytesIO() tree = ElementTree.ElementTree(self._root) indent(tree.getroot()) tree.write(f, encoding=encoding) @@ -361,7 +364,7 @@ def startHTML(title=None, cssReplacements={}): # write the css writer.begintag("style", type="text/css") css = defaultCSS - for before, after in cssReplacements.items(): + for before, after in list(cssReplacements.items()): css = css.replace(before, after) writer.write(css) writer.endtag("style") @@ -387,7 +390,7 @@ def finishHTML(writer): writer.endtag("html") # get the text text = "\n" - text += writer.compile() + text += writer.compile().decode("utf-8") text = text.replace("c_l_a_s_s", "class") text = text.replace("a_p_o_s_t_r_o_p_h_e", "'") text = text.replace("l_e_s_s", "<") diff --git a/Lib/woffTools/tools/validate.py b/Lib/woffTools/tools/validate.py index 064b3e3..0009792 100644 --- a/Lib/woffTools/tools/validate.py +++ b/Lib/woffTools/tools/validate.py @@ -6,9 +6,19 @@ This can also be used as a command line tool for validating WOFF files. """ +from __future__ import print_function +from __future__ import division # import +from future import standard_library +standard_library.install_aliases() +from builtins import str +from builtins import hex +from builtins import range +from past.builtins import basestring +from builtins import object +from past.utils import old_div import os import re import time @@ -17,7 +27,7 @@ import zlib import optparse import codecs -from cStringIO import StringIO +from io import BytesIO from xml.etree import ElementTree from xml.parsers.expat import ExpatError @@ -573,7 +583,7 @@ def _testHeaderSignature(data, reporter): """ header = unpackHeader(data) signature = header["signature"] - if signature != "wOFF": + if signature.decode("utf-8") != "wOFF": reporter.logError(message="Invalid signature: %s." % signature) return True else: @@ -589,7 +599,7 @@ def _testHeaderFlavor(data, reporter): """ header = unpackHeader(data) flavor = header["flavor"] - if flavor not in ("OTTO", "\000\001\000\000", "true"): + if flavor not in ("OTTO", "\000\001\000\000".encode('utf-8'), "true"): reporter.logWarning(message="Unknown flavor: %s." % flavor) else: try: @@ -877,9 +887,9 @@ def _testTableDirectory4ByteOffsets(data, reporter): tag = table["tag"] offset = table["offset"] if offset % 4: - reporter.logError(message="The \"%s\" table does not begin on a 4-byte boundary (%d)." % (tag, offset)) + reporter.logError(message="The \"%s\" table does not begin on a 4-byte boundary (%d)." % (tag.decode("utf-8"), offset.decode("utf-8"))) else: - reporter.logPass(message="The \"%s\" table begins on a 4-byte boundary." % tag) + reporter.logPass(message="The \"%s\" table begins on a 4-byte boundary." % tag.decode("utf-8")) def _testTableDirectoryPadding(data, reporter): """ @@ -912,10 +922,11 @@ def _testTableDirectoryPadding(data, reporter): paddingOffset = offset + length padding = data[paddingOffset:paddingOffset+paddingLength] expectedPadding = "\0" * paddingLength + expectedPadding = expectedPadding.encode('utf-8') if padding != expectedPadding: - reporter.logError(message="The \"%s\" table is not padded with null bytes." % tag) + reporter.logError(message="The \"%s\" table is not padded with null bytes." % tag.decode("utf-8")) else: - reporter.logPass(message="The \"%s\" table is padded with null bytes." % tag) + reporter.logPass(message="The \"%s\" table is padded with null bytes." % tag.decode("utf-8")) def _testTableDirectoryPositions(data, reporter): """ @@ -940,7 +951,7 @@ def _testTableDirectoryPositions(data, reporter): if tag == otherTag: continue if start >= otherStart and start < otherEnd: - reporter.logError(message="The \"%s\" table overlaps the \"%s\" table." % (tag, otherTag)) + reporter.logError(message="The \"%s\" table overlaps the \"%s\" table." % (tag.decode("utf-8"), otherTag.decode("utf-8"))) tablesWithProblems.add(tag) tablesWithProblems.add(otherTag) # test for invalid offset, length and combo @@ -961,17 +972,17 @@ def _testTableDirectoryPositions(data, reporter): # offset is before the beginning of the table data block if offset < minOffset: tablesWithProblems.add(tag) - message = "The \"%s\" table directory entry offset (%d) is before the start of the table data block (%d)." % (tag, offset, minOffset) + message = "The \"%s\" table directory entry offset (%d) is before the start of the table data block (%d)." % (tag.decode("utf-8"), offset, minOffset) reporter.logError(message=message) # offset is after the end of the table data block elif offset > tableDataEnd: tablesWithProblems.add(tag) - message = "The \"%s\" table directory entry offset (%d) is past the end of the table data block (%d)." % (tag, offset, tableDataEnd) + message = "The \"%s\" table directory entry offset (%d) is past the end of the table data block (%d)." % (tag.decode("utf-8"), offset, tableDataEnd) reporter.logError(message=message) # offset + length is after the end of the table tada block elif (offset + length) > tableDataEnd: tablesWithProblems.add(tag) - message = "The \"%s\" table directory entry offset (%d) + length (%d) is past the end of the table data block (%d)." % (tag, offset, length, tableDataEnd) + message = "The \"%s\" table directory entry offset (%d) + length (%d) is past the end of the table data block (%d)." % (tag.decode("utf-8"), offset, length, tableDataEnd) reporter.logError(message=message) # test for gaps tables = [] @@ -995,7 +1006,7 @@ def _testTableDirectoryPositions(data, reporter): tag = entry["tag"] if tag in tablesWithProblems: continue - reporter.logPass(message="The \"%s\" table directory entry has a valid offset and length." % tag) + reporter.logPass(message="The \"%s\" table directory entry has a valid offset and length." % tag.decode("utf-8")) def _testTableDirectoryCompressedLength(data, reporter): """ @@ -1008,9 +1019,9 @@ def _testTableDirectoryCompressedLength(data, reporter): compLength = table["compLength"] origLength = table["origLength"] if compLength > origLength: - reporter.logError(message="The \"%s\" table directory entry has a compressed length (%d) larger than the original length (%d)." % (tag, compLength, origLength)) + reporter.logError(message="The \"%s\" table directory entry has a compressed length (%d) larger than the original length (%d)." % (tag.decode("utf-8"), compLength, origLength)) else: - reporter.logPass(message="The \"%s\" table directory entry has proper compLength and origLength values." % tag) + reporter.logPass(message="The \"%s\" table directory entry has proper compLength and origLength values." % tag.decode("utf-8")) def _testTableDirectoryDecompressedLength(data, reporter): """ @@ -1032,9 +1043,9 @@ def _testTableDirectoryDecompressedLength(data, reporter): continue decompressedLength = len(decompressedData) if origLength != decompressedLength: - reporter.logError(message="The \"%s\" table directory entry has an original length (%d) that does not match the actual length of the decompressed data (%d)." % (tag, origLength, decompressedLength)) + reporter.logError(message="The \"%s\" table directory entry has an original length (%d) that does not match the actual length of the decompressed data (%d)." % (tag.decode("utf-8"), origLength, decompressedLength)) else: - reporter.logPass(message="The \"%s\" table directory entry has a proper original length compared to the actual decompressed data." % tag) + reporter.logPass(message="The \"%s\" table directory entry has a proper original length compared to the actual decompressed data." % tag.decode("utf-8")) def _testTableDirectoryChecksums(data, reporter): """ @@ -1052,17 +1063,17 @@ def _testTableDirectoryChecksums(data, reporter): # couldn't be decompressed. if decompressedData is None: continue - newChecksum = calcChecksum(tag, decompressedData) + newChecksum = calcChecksum(tag.decode("utf-8"), decompressedData) if newChecksum != origChecksum: - reporter.logError(message="The \"%s\" table directory entry original checksum (%s) does not match the checksum (%s) calculated from the data." % (tag, hex(origChecksum), hex(newChecksum))) + reporter.logError(message="The \"%s\" table directory entry original checksum (%s) does not match the checksum (%s) calculated from the data." % (tag.decode("utf-8"), hex(origChecksum), hex(newChecksum))) else: - reporter.logPass(message="The \"%s\" table directory entry original checksum is correct." % tag) + reporter.logPass(message="The \"%s\" table directory entry original checksum is correct." % tag.decode("utf-8")) # check the head checksum adjustment - if "head" not in tables: + if b"head" not in tables: reporter.logWarning(message="The font does not contain a \"head\" table.") else: newChecksum = calcHeadChecksum(data) - data = tables["head"] + data = tables[b"head"] try: checksum = struct.unpack(">L", data[8:12])[0] if checksum != newChecksum: @@ -1117,9 +1128,9 @@ def _testTableDataDecompression(data, reporter): entryData = data[offset:offset+compLength] try: decompressed = zlib.decompress(entryData) - reporter.logPass(message="The \"%s\" table data can be decompressed with zlib." % tag) + reporter.logPass(message="The \"%s\" table data can be decompressed with zlib." % tag.decode("utf-8")) except zlib.error: - reporter.logError(message="The \"%s\" table data can not be decompressed with zlib." % tag) + reporter.logError(message="The \"%s\" table data can not be decompressed with zlib." % tag.decode("utf-8")) # ---------------- # Tests: Metadata @@ -1318,7 +1329,7 @@ def _validateMetadataElement(element, spec, reporter, parentTree=[]): haveError = False # unknown attributes knownAttributes = [] - for attrib in spec["requiredAttributes"].keys() + spec["recommendedAttributes"].keys() + spec["optionalAttributes"].keys(): + for attrib in list(spec["requiredAttributes"].keys()) + list(spec["recommendedAttributes"].keys()) + list(spec["optionalAttributes"].keys()): attrib = _parseAttribute(attrib) knownAttributes.append(attrib) for attrib in sorted(element.attrib.keys()): @@ -1353,7 +1364,7 @@ def _validateMetadataElement(element, spec, reporter, parentTree=[]): if e: haveError = True # unknown child-elements - knownChildElements = spec["requiredChildElements"].keys() + spec["recommendedChildElements"].keys() + spec["optionalChildElements"].keys() + knownChildElements = list(spec["requiredChildElements"].keys()) + list(spec["recommendedChildElements"].keys()) + list(spec["optionalChildElements"].keys()) for childElement in element: if childElement.tag not in knownChildElements: _logMetadataResult( @@ -1648,17 +1659,18 @@ def calcPaddingLength(length): return 4 - (length % 4) def padData(data): - data += "\0" * calcPaddingLength(len(data)) + pad = "\0" * calcPaddingLength(len(data)) + data += pad.encode('utf-8') return data def sumDataULongs(data): - longs = struct.unpack(">%dL" % (len(data) / 4), data) + longs = struct.unpack(">%dL" % (old_div(len(data), 4)), data) value = sum(longs) % (2 ** 32) return value def calcChecksum(tag, data): if tag == "head": - data = data[:8] + "\0\0\0\0" + data[12:] + data = data[:8] + b"\0\0\0\0" + data[12:] data = padData(data) value = sumDataULongs(data) return value @@ -1694,7 +1706,7 @@ def calcHeadChecksum(data): for tag, sfntEntry in sorted(sfntEntries.items()): sfntData += structPack(sfntDirectoryEntryFormat, sfntEntry) # calculate - checkSums = [entry["checkSum"] for entry in sfntEntries.values()] + checkSums = [entry["checkSum"] for entry in list(sfntEntries.values())] checkSums.append(sumDataULongs(sfntData)) checkSum = sum(checkSums) checkSum = (0xB1B0AFBA - checkSum) & 0xffffffff @@ -1733,7 +1745,7 @@ def write(self, text): self._elements[-1].text += text def compile(self, encoding="utf-8"): - f = StringIO() + f = BytesIO() tree = ElementTree.ElementTree(self._root) indent(tree.getroot()) tree.write(f, encoding=encoding) @@ -2275,7 +2287,7 @@ def startHTML(title=None, cssReplacements={}): # write the css writer.begintag("style", type="text/css") css = defaultCSS - for before, after in cssReplacements.items(): + for before, after in list(cssReplacements.items()): css = css.replace(before, after) writer.write(css) writer.endtag("style") @@ -2301,7 +2313,7 @@ def finishHTML(writer): writer.endtag("html") # get the text text = "\n" - text += writer.compile() + text += writer.compile().decode("utf-8") text = text.replace("c_l_a_s_s", "class") text = text.replace("a_p_o_s_t_r_o_p_h_e", "'") text = text.replace("l_e_s_s", "<") @@ -2448,7 +2460,7 @@ def validateFont(path, options, writeFile=True): reportPath = os.path.join(directory, fileName) reportPath = findUniqueFileName(reportPath) f = open(reportPath, "wb") - f.write(report) + f.write(report.encode('utf-8')) f.close() return reportPath, report @@ -2465,7 +2477,7 @@ def validateFont(path, options, writeFile=True): """ def main(): - parser = optparse.OptionParser(usage=usage, description=description, version="%prog 0.1beta") + parser = optparse.OptionParser(usage=usage, description=description, version="%prog 0.2") parser.add_option("-d", dest="outputDirectory", help="Output directory. The default is to output the report into the same directory as the font file.") parser.add_option("-o", dest="outputFileName", help="Output file name. The default is \"fontfilename_validate.html\".") parser.set_defaults(excludeTests=[]) @@ -2474,17 +2486,18 @@ def main(): options.outputFormat = "html" options.testGroups = None # don't expose this to the commandline. it's for testing only. if outputDirectory is not None and not os.path.exists(outputDirectory): - print "Directory does not exist:", outputDirectory + print("Directory does not exist:", outputDirectory) sys.exit() for fontPath in args: if not os.path.exists(fontPath): - print "File does not exist:", fontPath + print("File does not exist:", fontPath) sys.exit() else: - print "Testing: %s..." % fontPath - fontPath = fontPath.decode("utf-8") + print("Testing: %s..." % fontPath) + if hasattr(fontPath, "decode"): + fontPath = fontPath.decode("utf-8") outputPath, report = validateFont(fontPath, options) - print "Wrote report to: %s" % outputPath + print("Wrote report to: %s" % outputPath) if __name__ == "__main__": main() diff --git a/setup.py b/setup.py index 12f3e9b..9ab3442 100644 --- a/setup.py +++ b/setup.py @@ -1,25 +1,25 @@ #!/usr/bin/env python +from __future__ import print_function import sys from setuptools import setup try: import fontTools except: - print "*** Warning: woffTools requires FontTools, see:" - print " fonttools.sf.net" + print("*** Warning: woffTools requires FontTools, see:") + print(" fonttools.sf.net") setup( name="woffTools", - version="0.1beta", + version="0.2", description="A set of tools for working with WOFF files.", author="Tal Leming", author_email="tal@typesupply.com", url="https://github.com/typesupply/woffTools", license="MIT", packages=[ - "", "woffTools", "woffTools.tools", "woffTools.test" diff --git a/woff-all b/woff-all index 6b52369..1623153 100644 --- a/woff-all +++ b/woff-all @@ -1,5 +1,6 @@ #! /usr/bin/env python +from __future__ import print_function doc = """woff-all [options] fontpath1 fontpath2" This tool runs woof-validate, woff-info, woff-proof @@ -15,12 +16,12 @@ from woffTools.tools import proof from woffTools.tools import css if len(sys.argv) > 1 and sys.argv[1] == "-h": - print doc + print(doc) sys.exit() for i in sys.argv: if i.startswith("-") and not i == "-d": - print "Only the -d argument may be used with this tool." + print("Only the -d argument may be used with this tool.") sys.exit() modules = [validate, info, proof, css]