def decompile(self, data, ttFont): # read table header sstruct.unpack(sbixHeaderFormat, data[: sbixHeaderFormatSize], self) # collect offsets to individual bitmap sets in self.bitmapSetOffsets for i in range(self.numSets): myOffset = sbixHeaderFormatSize + i * sbixBitmapSetOffsetFormatSize offsetEntry = sbixBitmapSetOffset() sstruct.unpack(sbixBitmapSetOffsetFormat, \ data[myOffset: myOffset + sbixBitmapSetOffsetFormatSize], \ offsetEntry) self.bitmapSetOffsets.append(offsetEntry.offset) # decompile BitmapSets for i in range(self.numSets - 1, -1, -1): myBitmapSet = BitmapSet(rawdata=data[self.bitmapSetOffsets[i]:]) data = data[:self.bitmapSetOffsets[i]] myBitmapSet.decompile(ttFont) # print " BitmapSet length: %xh" % len(bitmapSetData) # print "Number of Bitmaps:", myBitmapSet.numBitmaps if myBitmapSet.size in self.bitmapSets: from fontTools import ttLib raise (ttLib.TTLibError, "Pixel 'size' must be unique for each BitmapSet") self.bitmapSets[myBitmapSet.size] = myBitmapSet # after the bitmaps have been extracted, we don't need the offsets anymore del self.bitmapSetOffsets
def decompile(self, ttFont): self.glyphName = ttFont.getGlyphName(self.gid) if self.rawdata is None: from fontTools import ttLib raise (ttLib.TTLibError, "No table data to decompile.") if len(self.rawdata) > 0: if len(self.rawdata) < sbixBitmapHeaderFormatSize: from fontTools import ttLib #print "Bitmap %i header too short: Expected %x, got %x." % (self.gid, sbixBitmapHeaderFormatSize, len(self.rawdata)) raise (ttLib.TTLibError, "Bitmap header too short.") sstruct.unpack(sbixBitmapHeaderFormat, self.rawdata[:sbixBitmapHeaderFormatSize], self) if self.imageFormatTag == "dupe": # bitmap is a reference to another glyph's bitmap gid, = struct.unpack(">H", self.rawdata[sbixBitmapHeaderFormatSize:]) self.referenceGlyphName = ttFont.getGlyphName(gid) else: self.imageData = self.rawdata[sbixBitmapHeaderFormatSize:] self.referenceGlyphName = None # clean up del self.rawdata del self.gid
def decompile(self, data): # header; FontRec sstruct.unpack(nfntHeaderFormat, data[:headerSize], self) # assert self.fRectHeight == (self.ascent + self.descent) # rest tableSize = 2 * (self.lastChar - self.firstChar + 3) bitmapSize = 2 * self.rowWords * self.fRectHeight self.bits = data[headerSize:headerSize + bitmapSize] # XXX deal with self.nDescent being a positive number assert (headerSize + bitmapSize + tableSize - 16) / 2 == self.owTLoc # ugh... locTable = data[headerSize + bitmapSize:headerSize + bitmapSize + tableSize] if len(locTable) <> tableSize: raise ValueError, 'invalid NFNT format' owTable = data[headerSize + bitmapSize + tableSize:headerSize + bitmapSize + 2 * tableSize] if len(owTable) <> tableSize: raise ValueError, 'invalid NFNT format' # fill tables self.offsetTable = [] self.widthTable = [] self.locTable = [] for i in range(0, tableSize, 2): self.offsetTable.append(ord(owTable[i])) self.widthTable.append(ord(owTable[i + 1])) loc, = struct.unpack("h", locTable[i:i + 2]) self.locTable.append(loc)
def decompile(self, ttFont): self.glyphName = ttFont.getGlyphName(self.gid) if self.rawdata is None: from fontTools import ttLib raise (ttLib.TTLibError, "No table data to decompile.") if len(self.rawdata) > 0: if len(self.rawdata) < sbixBitmapHeaderFormatSize: from fontTools import ttLib # print "Bitmap %i header too short: Expected %x, got %x." % (self.gid, sbixBitmapHeaderFormatSize, len(self.rawdata)) raise (ttLib.TTLibError, "Bitmap header too short.") sstruct.unpack(sbixBitmapHeaderFormat, self.rawdata[:sbixBitmapHeaderFormatSize], self) if self.imageFormatTag == "dupe": # bitmap is a reference to another glyph's bitmap gid, = struct.unpack(">H", self.rawdata[sbixBitmapHeaderFormatSize:]) self.referenceGlyphName = ttFont.getGlyphName(gid) else: self.imageData = self.rawdata[sbixBitmapHeaderFormatSize:] self.referenceGlyphName = None # clean up del self.rawdata del self.gid
def decompile(self, ttFont): if self.data is None: from fontTools import ttLib raise (ttLib.TTLibError, "No table data to decompile.") if len(self.data) < sbixBitmapSetHeaderFormatSize: from fontTools import ttLib raise (ttLib.TTLibError, "BitmapSet header too short: Expected %x, got %x.") \ % (sbixBitmapSetHeaderFormatSize, len(self.data)) # read BitmapSet header from raw data sstruct.unpack(sbixBitmapSetHeaderFormat, self.data[:sbixBitmapSetHeaderFormatSize], self) # calculate number of bitmaps firstBitmapOffset, = struct.unpack(">L", \ self.data[ sbixBitmapSetHeaderFormatSize: sbixBitmapSetHeaderFormatSize + sbixBitmapOffsetEntryFormatSize]) self.numBitmaps = (firstBitmapOffset - sbixBitmapSetHeaderFormatSize) / sbixBitmapOffsetEntryFormatSize - 1 # ^ -1 because there's one more offset than bitmaps # build offset list for single bitmap offsets self.bitmapOffsets = [] for i in range(self.numBitmaps + 1): # + 1 because there's one more offset than bitmaps start = i * sbixBitmapOffsetEntryFormatSize + sbixBitmapSetHeaderFormatSize myOffset, = struct.unpack(">L", self.data[start: start + sbixBitmapOffsetEntryFormatSize]) self.bitmapOffsets.append(myOffset) # iterate through offset list and slice raw data into bitmaps for i in range(self.numBitmaps): myBitmap = Bitmap(rawdata=self.data[self.bitmapOffsets[i]: self.bitmapOffsets[i + 1]], gid=i) myBitmap.decompile(ttFont) self.bitmaps[myBitmap.glyphName] = myBitmap del self.bitmapOffsets del self.data
def decompile(self, ttFont): if self.data is None: from fontTools import ttLib raise(ttLib.TTLibError, "No table data to decompile.") if len(self.data) < sbixBitmapSetHeaderFormatSize: from fontTools import ttLib raise(ttLib.TTLibError, "BitmapSet header too short: Expected %x, got %x.") \ % (sbixBitmapSetHeaderFormatSize, len(self.data)) # read BitmapSet header from raw data sstruct.unpack(sbixBitmapSetHeaderFormat, self.data[:sbixBitmapSetHeaderFormatSize], self) # calculate number of bitmaps firstBitmapOffset, = struct.unpack(">L", \ self.data[sbixBitmapSetHeaderFormatSize : sbixBitmapSetHeaderFormatSize + sbixBitmapOffsetEntryFormatSize]) self.numBitmaps = (firstBitmapOffset - sbixBitmapSetHeaderFormatSize) / sbixBitmapOffsetEntryFormatSize - 1 # ^ -1 because there's one more offset than bitmaps # build offset list for single bitmap offsets self.bitmapOffsets = [] for i in range(self.numBitmaps + 1): # + 1 because there's one more offset than bitmaps start = i * sbixBitmapOffsetEntryFormatSize + sbixBitmapSetHeaderFormatSize myOffset, = struct.unpack(">L", self.data[start : start + sbixBitmapOffsetEntryFormatSize]) self.bitmapOffsets.append(myOffset) # iterate through offset list and slice raw data into bitmaps for i in range(self.numBitmaps): myBitmap = Bitmap(rawdata=self.data[self.bitmapOffsets[i] : self.bitmapOffsets[i+1]], gid=i) myBitmap.decompile(ttFont) self.bitmaps[myBitmap.glyphName] = myBitmap del self.bitmapOffsets del self.data
def decompile(self, data, ttFont): # read table header sstruct.unpack(sbixHeaderFormat, data[ : sbixHeaderFormatSize], self) # collect offsets to individual bitmap sets in self.bitmapSetOffsets for i in range(self.numSets): myOffset = sbixHeaderFormatSize + i * sbixBitmapSetOffsetFormatSize offsetEntry = sbixBitmapSetOffset() sstruct.unpack(sbixBitmapSetOffsetFormat, \ data[myOffset : myOffset+sbixBitmapSetOffsetFormatSize], \ offsetEntry) self.bitmapSetOffsets.append(offsetEntry.offset) # decompile BitmapSets for i in range(self.numSets-1, -1, -1): myBitmapSet = BitmapSet(rawdata=data[self.bitmapSetOffsets[i]:]) data = data[:self.bitmapSetOffsets[i]] myBitmapSet.decompile(ttFont) #print " BitmapSet length: %xh" % len(bitmapSetData) #print "Number of Bitmaps:", myBitmapSet.numBitmaps if myBitmapSet.size in self.bitmapSets: from fontTools import ttLib raise(ttLib.TTLibError, "Pixel 'size' must be unique for each BitmapSet") self.bitmapSets[myBitmapSet.size] = myBitmapSet # after the bitmaps have been extracted, we don't need the offsets anymore del self.bitmapSetOffsets
def __init__(self, refNum): self.__fileName = array.array("c", "\0" * 64) sstruct.unpack(_FCBPBFormat, "\0" * sstruct.calcsize(_FCBPBFormat), self) self.ioNamePtr = self.__fileName.buffer_info()[0] self.ioRefNum = refNum self.ioVRefNum = GetVRefNum(refNum) self.__haveInfo = 0
def _getheader(self): data = self.FOND.data sstruct.unpack(headerformat, data[:28], self) self.ffProperty = struct.unpack(">9h", data[28:46]) self.ffIntl = struct.unpack(">hh", data[46:50]) self.ffVersion, = struct.unpack(">h", data[50:FONDheadersize]) if DEBUG: self._rawheader = data[:FONDheadersize] self.parsedthings.append((0, FONDheadersize, 'header'))
def getInfo(self): if self.__haveInfo: return data = sstruct.pack(_FCBPBFormat, self) buf = array.array("c", data) ptr = buf.buffer_info()[0] err = _getInfo(ptr) if err: raise Res.Error("can't get file info", err) sstruct.unpack(_FCBPBFormat, buf.tostring(), self) self.__haveInfo = 1
def decompile(self, data, ttFont): sstruct.unpack(postFormat, data[:postFormatSize], self) data = data[postFormatSize:] if self.formatType == 1.0: self.decode_format_1_0(data, ttFont) elif self.formatType == 2.0: self.decode_format_2_0(data, ttFont) elif self.formatType == 3.0: self.decode_format_3_0(data, ttFont) else: # supported format raise ttLib.TTLibError("'post' table format %f not supported" % self.formatType)
def decompile(self, data, ttFont): sstruct.unpack(postFormat, data[:postFormatSize], self) data = data[postFormatSize:] if self.formatType == 1.0: self.decode_format_1_0(data, ttFont) elif self.formatType == 2.0: self.decode_format_2_0(data, ttFont) elif self.formatType == 3.0: self.decode_format_3_0(data, ttFont) else: # supported format raise ttLib.TTLibError, "'post' table format %f not supported" % self.formatType
def test_incorrect_compressed_size(self): data = self.file.read(woff2DirectorySize) header = sstruct.unpack(woff2DirectoryFormat, data) header['totalCompressedSize'] = 0 data = sstruct.pack(woff2DirectoryFormat, header) with self.assertRaises(brotli.error): WOFF2Reader(BytesIO(data + self.file.read()))
def test_incorrect_file_size(self): data = self.file.read(woff2DirectorySize) header = sstruct.unpack(woff2DirectoryFormat, data) header['length'] -= 1 data = sstruct.pack(woff2DirectoryFormat, header) with self.assertRaisesRegex( ttLib.TTLibError, "doesn't match the actual file size"): WOFF2Reader(BytesIO(data + self.file.read()))
def __init__(self, file, checkChecksums=1): self.file = file self.checkChecksums = checkChecksums # unpack the header self.file.seek(0) bytes = self.file.read(woffHeaderSize) if len(bytes) != woffHeaderSize: raise WOFFLibError("Not a properly formatted WOFF file.") sstruct.unpack(woffHeaderFormat, bytes, self) if self.signature != "wOFF": raise WOFFLibError("Not a properly formatted WOFF file.") # unpack the directory self.tables = {} for i in range(self.numTables): entry = WOFFDirectoryEntry() entry.fromFile(self.file) self.tables[entry.tag] = entry
def test_incorrect_file_size(self): data = self.file.read(woff2DirectorySize) header = sstruct.unpack(woff2DirectoryFormat, data) header['length'] -= 1 data = sstruct.pack(woff2DirectoryFormat, header) with self.assertRaisesRegex(ttLib.TTLibError, "doesn't match the actual file size"): WOFF2Reader(BytesIO(data + self.file.read()))
def __init__(self, file, checkChecksums=1, fontNumber=-1): self.file = file self.checkChecksums = checkChecksums self.flavor = None self.flavorData = None self.DirectoryEntry = SFNTDirectoryEntry self.sfntVersion = self.file.read(4) self.file.seek(0) if self.sfntVersion == "ttcf": sstruct.unpack(ttcHeaderFormat, self.file.read(ttcHeaderSize), self) assert self.Version == 0x00010000 or self.Version == 0x00020000, "unrecognized TTC version 0x%08x" % self.Version if not 0 <= fontNumber < self.numFonts: from fontTools import ttLib raise ttLib.TTLibError, "specify a font number between 0 and %d (inclusive)" % ( self.numFonts - 1) offsetTable = struct.unpack(">%dL" % self.numFonts, self.file.read(self.numFonts * 4)) if self.Version == 0x00020000: pass # ignoring version 2.0 signatures self.file.seek(offsetTable[fontNumber]) sstruct.unpack(sfntDirectoryFormat, self.file.read(sfntDirectorySize), self) elif self.sfntVersion == "wOFF": self.flavor = "woff" self.DirectoryEntry = WOFFDirectoryEntry sstruct.unpack(woffDirectoryFormat, self.file.read(woffDirectorySize), self) else: sstruct.unpack(sfntDirectoryFormat, self.file.read(sfntDirectorySize), self) if self.sfntVersion not in ("\000\001\000\000", "OTTO", "true"): from fontTools import ttLib raise ttLib.TTLibError, "Not a TrueType or OpenType font (bad sfntVersion)" self.tables = {} for i in range(self.numTables): entry = self.DirectoryEntry() entry.fromFile(self.file) if entry.length > 0: self.tables[entry.tag] = entry else: # Ignore zero-length tables. This doesn't seem to be documented, # yet it's apparently how the Windows TT rasterizer behaves. # Besides, at least one font has been sighted which actually # *has* a zero-length table. pass # Load flavor data if any if self.flavor == "woff": self.flavorData = WOFFFlavorData(self)
def decompile(self, data, ttFont): dummy, data = sstruct.unpack2(OS2_format_0, data, self) if self.version == 1 and not data: # workaround for buggy Apple fonts self.version = 0 if self.version == 1: sstruct.unpack2(OS2_format_1_addition, data, self) elif self.version in (2, 3, 4): sstruct.unpack2(OS2_format_2_addition, data, self) elif self.version != 0: from fontTools import ttLib raise ttLib.TTLibError("unknown format for OS/2 table: version %s" % self.version) self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
def decompile(self, data, ttFont): dummy, data = sstruct.unpack2(OS2_format_0, data, self) if self.version == 1 and not data: # workaround for buggy Apple fonts self.version = 0 if self.version == 1: sstruct.unpack2(OS2_format_1_addition, data, self) elif self.version in (2, 3, 4): sstruct.unpack2(OS2_format_2_addition, data, self) elif self.version <> 0: from fontTools import ttLib raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
def __init__(self, file, checkChecksums=1, fontNumber=-1): self.file = file self.checkChecksums = checkChecksums self.flavor = None self.flavorData = None self.DirectoryEntry = SFNTDirectoryEntry self.sfntVersion = self.file.read(4) self.file.seek(0) if self.sfntVersion == "ttcf": sstruct.unpack(ttcHeaderFormat, self.file.read(ttcHeaderSize), self) assert self.Version == 0x00010000 or self.Version == 0x00020000, "unrecognized TTC version 0x%08x" % self.Version if not 0 <= fontNumber < self.numFonts: from fontTools import ttLib raise ttLib.TTLibError, "specify a font number between 0 and %d (inclusive)" % (self.numFonts - 1) offsetTable = struct.unpack(">%dL" % self.numFonts, self.file.read(self.numFonts * 4)) if self.Version == 0x00020000: pass # ignoring version 2.0 signatures self.file.seek(offsetTable[fontNumber]) sstruct.unpack(sfntDirectoryFormat, self.file.read(sfntDirectorySize), self) elif self.sfntVersion == "wOFF": self.flavor = "woff" self.DirectoryEntry = WOFFDirectoryEntry sstruct.unpack(woffDirectoryFormat, self.file.read(woffDirectorySize), self) else: sstruct.unpack(sfntDirectoryFormat, self.file.read(sfntDirectorySize), self) if self.sfntVersion not in ("\000\001\000\000", "OTTO", "true"): from fontTools import ttLib raise ttLib.TTLibError, "Not a TrueType or OpenType font (bad sfntVersion)" self.tables = {} for i in range(self.numTables): entry = self.DirectoryEntry() entry.fromFile(self.file) if entry.length > 0: self.tables[entry.tag] = entry else: # Ignore zero-length tables. This doesn't seem to be documented, # yet it's apparently how the Windows TT rasterizer behaves. # Besides, at least one font has been sighted which actually # *has* a zero-length table. pass # Load flavor data if any if self.flavor == "woff": self.flavorData = WOFFFlavorData(self)
def decompile(self, data, ttFont): dummy, data = sstruct.unpack2(OS2_format_0, data, self) # workarounds for buggy fonts (Apple, mona) if not data: self.version = 0 elif len(data) == sstruct.calcsize(OS2_format_1_addition): self.version = 1 elif len(data) == sstruct.calcsize(OS2_format_2_addition): if self.version not in (2, 3, 4): self.version = 1 else: from fontTools import ttLib raise ttLib.TTLibError, "unknown format for OS/2 table (incorrect length): version %s" % (self.version, len(data)) if self.version == 1: sstruct.unpack2(OS2_format_1_addition, data, self) elif self.version in (2, 3, 4): sstruct.unpack2(OS2_format_2_addition, data, self) elif self.version <> 0: from fontTools import ttLib raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
def decompile(self, data, ttFont): dummy, data = sstruct.unpack2(OS2_format_0, data, self) # workarounds for buggy fonts (Apple, mona) if not data: self.version = 0 elif len(data) == sstruct.calcsize(OS2_format_1_addition): self.version = 1 elif len(data) == sstruct.calcsize(OS2_format_2_addition): if self.version not in (2, 3, 4): self.version = 1 else: from fontTools import ttLib raise ttLib.TTLibError, "unknown format for OS/2 table (incorrect length): version %s" % ( self.version, len(data)) if self.version == 1: sstruct.unpack2(OS2_format_1_addition, data, self) elif self.version in (2, 3, 4): sstruct.unpack2(OS2_format_2_addition, data, self) elif self.version <> 0: from fontTools import ttLib raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
def __init__(self, file, checkChecksums=1, fontNumber=-1): self.file = file self.checkChecksums = checkChecksums data = self.file.read(sfntDirectorySize) if len(data) != sfntDirectorySize: from fontTools import ttLib raise ttLib.TTLibError( "Not a TrueType or OpenType font (not enough data)") sstruct.unpack(sfntDirectoryFormat, data, self) if self.sfntVersion == b"ttcf": assert ttcHeaderSize == sfntDirectorySize sstruct.unpack(ttcHeaderFormat, data, self) assert self.Version == b'\0\1\0\0' or self.Version == b'\0\2\0\0', "unrecognized TTC version 0x%08x" % self.Version if not 0 <= fontNumber < self.numFonts: from fontTools import ttLib raise ttLib.TTLibError( "specify a font number between 0 and %d (inclusive)" % (self.numFonts - 1)) offsetTable = struct.unpack(">%dL" % self.numFonts, self.file.read(self.numFonts * 4)) if self.Version == b'\0\2\0\0': pass # ignoring version 2.0 signatures self.file.seek(offsetTable[fontNumber]) data = self.file.read(sfntDirectorySize) sstruct.unpack(sfntDirectoryFormat, data, self) if self.sfntVersion not in (b'\0\1\0\0', b"OTTO", b"true"): from fontTools import ttLib raise ttLib.TTLibError( "Not a TrueType or OpenType font (bad sfntVersion)") self.tables = {} for i in range(self.numTables): entry = SFNTDirectoryEntry() entry.fromFile(self.file) if entry.length > 0: self.tables[entry.tag] = entry else: # Ignore zero-length tables. This doesn't seem to be documented, # yet it's apparently how the Windows TT rasterizer behaves. # Besides, at least one font has been sighted which actually # *has* a zero-length table. pass
def __init__(self, file, checkChecksums=1, fontNumber=-1): self.file = file self.checkChecksums = checkChecksums data = self.file.read(sfntDirectorySize) if len(data) != sfntDirectorySize: from fontTools import ttLib raise ttLib.TTLibError("Not a TrueType or OpenType font (not enough data)") sstruct.unpack(sfntDirectoryFormat, data, self) if self.sfntVersion == b"ttcf": assert ttcHeaderSize == sfntDirectorySize sstruct.unpack(ttcHeaderFormat, data, self) assert self.Version == b'\0\1\0\0' or self.Version == b'\0\2\0\0', "unrecognized TTC version 0x%08x" % self.Version if not 0 <= fontNumber < self.numFonts: from fontTools import ttLib raise ttLib.TTLibError("specify a font number between 0 and %d (inclusive)" % (self.numFonts - 1)) offsetTable = struct.unpack(">%dL" % self.numFonts, self.file.read(self.numFonts * 4)) if self.Version == b'\0\2\0\0': pass # ignoring version 2.0 signatures self.file.seek(offsetTable[fontNumber]) data = self.file.read(sfntDirectorySize) sstruct.unpack(sfntDirectoryFormat, data, self) if self.sfntVersion not in (b'\0\1\0\0', b"OTTO", b"true"): from fontTools import ttLib raise ttLib.TTLibError("Not a TrueType or OpenType font (bad sfntVersion)") self.tables = {} for i in range(self.numTables): entry = SFNTDirectoryEntry() entry.fromFile(self.file) if entry.length > 0: self.tables[entry.tag] = entry else: # Ignore zero-length tables. This doesn't seem to be documented, # yet it's apparently how the Windows TT rasterizer behaves. # Besides, at least one font has been sighted which actually # *has* a zero-length table. pass
def fromString(self, str): sstruct.unpack(sfntDirectoryEntryFormat, str, self)
def checkSFNTConformance(file): """ This function checks a SFNT file to see if it meets the conformance recomendations in the WOFF specification. This includes: - searchRange must be correct. - entrySelector must be correct. - rangeShift must be correct. - offset to each table must be after the table directory and before the end of the file. - offset + length of each table must not extend past the end of the file. - the table directory must be in ascending order. - tables must be padded to 4 byte boundaries. - the final table must be padded to a 4 byte boundary. - the gaps between table data blocks must not be more than necessary to pad the table to a 4 byte boundary. - the gap between the end of the final table and the end of the file must not be more than necessary to pad the table to a four byte boundary. - the checksums for each table in the table directory must be correct. - the head checkSumAdjustment must be correct. - the padding bytes must be null. The returned value of this function will be a list. If any errors were found, they will be represented as strings in the list. """ # load the data closeFile = False if not hasattr(file, "read"): file = open(file, "rb") closeFile = True data = file.read() if closeFile: file.close() # storage errors = [] # unpack the header headerData = data[:sfntDirectorySize] header = sstruct.unpack(sfntDirectoryFormat, headerData) # unpack the table directory numTables = header["numTables"] directoryData = data[sfntDirectorySize:sfntDirectorySize + (sfntDirectoryEntrySize * numTables)] tableDirectory = [] for index in range(numTables): entry = sstruct.unpack(sfntDirectoryEntryFormat, directoryData[:sfntDirectoryEntrySize]) tableDirectory.append(entry) directoryData = directoryData[sfntDirectoryEntrySize:] # sanity testing errors += _testOffsetBoundaryValidity(len(data), tableDirectory) errors += _testLengthBoundaryValidity(len(data), tableDirectory) # if one or more errors have already been found, something # is very wrong and this should come to a screeching halt. if errors: return errors # junk at the beginning of the file errors += _testJunkAtTheBeginningOfTheFile(header) # test directory order errors += _testDirectoryOrder(tableDirectory) # load the table data for entry in tableDirectory: offset = entry["offset"] length = entry["length"] entry["data"] = data[offset:offset + length] # test for overlaps errors += _testOverlaps(tableDirectory) # test for padding errors += _testOffsets(tableDirectory) # test the final table padding errors += _testFinalTablePadding(len(data), numTables, tableDirectory[-1]["tag"]) # test for gaps errors += _testGaps(tableDirectory) # test for a gap at the end of the file errors += _testGapAfterFinalTable(len(data), tableDirectory) # test padding value errors += _testPaddingValue(tableDirectory, data) # validate checksums errors += _testCheckSums(tableDirectory) errors += _testHeadCheckSum(header, tableDirectory) # done. return errors
def fromFile(self, file): sstruct.unpack(self.format, file.read(self.formatSize), self)
def fromFile(self, file): sstruct.unpack(sfntDirectoryEntryFormat, file.read(sfntDirectoryEntrySize), self)
def decompile(self, data, ttFont): sstruct.unpack(vheaFormat, data, self)
def test_num_tables(self): tags = [t for t in self.font.keys() if t not in ('GlyphOrder', 'DSIG')] data = self.file.read(woff2DirectorySize) header = sstruct.unpack(woff2DirectoryFormat, data) self.assertEqual(header['numTables'], len(tags))
def checkSFNTConformance(file): """ This function checks a SFNT file to see if it meets the conformance recomendations in the WOFF specification. This includes: - searchRange must be correct. - entrySelector must be correct. - rangeShift must be correct. - offset to each table must be after the table directory and before the end of the file. - offset + length of each table must not extend past the end of the file. - the table directory must be in ascending order. - tables must be padded to 4 byte boundaries. - the final table must be padded to a 4 byte boundary. - the gaps between table data blocks must not be more than necessary to pad the table to a 4 byte boundary. - the gap between the end of the final table and the end of the file must not be more than necessary to pad the table to a four byte boundary. - the checksums for each table in the table directory must be correct. - the head checkSumAdjustment must be correct. - the padding bytes must be null. The returned value of this function will be a list. If any errors were found, they will be represented as strings in the list. """ # load the data closeFile = False if not hasattr(file, "read"): file = open(file, "rb") closeFile = True data = file.read() if closeFile: file.close() # storage errors = [] # unpack the header headerData = data[:sfntDirectorySize] header = sstruct.unpack(sfntDirectoryFormat, headerData) # unpack the table directory numTables = header["numTables"] directoryData = data[sfntDirectorySize : sfntDirectorySize + (sfntDirectoryEntrySize * numTables)] tableDirectory = [] for index in range(numTables): entry = sstruct.unpack(sfntDirectoryEntryFormat, directoryData[:sfntDirectoryEntrySize]) tableDirectory.append(entry) directoryData = directoryData[sfntDirectoryEntrySize:] # sanity testing errors += _testOffsetBoundaryValidity(len(data), tableDirectory) errors += _testLengthBoundaryValidity(len(data), tableDirectory) # if one or more errors have already been found, something # is very wrong and this should come to a screeching halt. if errors: return errors # junk at the beginning of the file errors += _testJunkAtTheBeginningOfTheFile(header) # test directory order errors += _testDirectoryOrder(tableDirectory) # load the table data for entry in tableDirectory: offset = entry["offset"] length = entry["length"] entry["data"] = data[offset:offset+length] # test for overlaps errors += _testOverlaps(tableDirectory) # test for padding errors += _testOffsets(tableDirectory) # test the final table padding errors += _testFinalTablePadding(len(data), numTables, tableDirectory[-1]["tag"]) # test for gaps errors += _testGaps(tableDirectory) # test for a gap at the end of the file errors += _testGapAfterFinalTable(len(data), tableDirectory) # test padding value errors += _testPaddingValue(tableDirectory, data) # validate checksums errors += _testCheckSums(tableDirectory) errors += _testHeadCheckSum(header, tableDirectory) # done. return errors
def fromString(self, str): sstruct.unpack(self.format, str, self)