# Source code for fontTools.ttLib.tables._h_e_a_d

    from fontTools.misc import sstruct
    from fontTools.misc.fixedTools import floatToFixedToStr, strToFixedToFloat
    from fontTools.misc.textTools import safeEval, num2binary, binary2num
    from fontTools.misc.timeTools import timestampFromString, timestampToString, timestampNow
    from fontTools.misc.timeTools import epoch_diff as mac_epoch_diff # For backward compat
    from fontTools.misc.arrayTools import intRect, unionRect
    from . import DefaultTable
    import logging

    log = logging.getLogger(__name__)

    headFormat = """
    		>	# big endian
    		tableVersion:       16.16F
    		fontRevision:       16.16F
    		checkSumAdjustment: I
    		magicNumber:        I
    		flags:              H
    		unitsPerEm:         H
    		created:            Q
    		modified:           Q
    		xMin:               h
    		yMin:               h
    		xMax:               h
    		yMax:               h
    		macStyle:           H
    		lowestRecPPEM:      H
    		fontDirectionHint:  h
    		indexToLocFormat:   h
    		glyphDataFormat:    h
    """

    class table__h_e_a_d(DefaultTable.DefaultTable):

    	dependencies = ['maxp', 'loca', 'CFF ', 'CFF2']

    	def decompile(self, data, ttFont):
    		dummy, rest = sstruct.unpack2(headFormat, data, self)
    		if rest:
    			# this is quite illegal, but there seem to be fonts out there that do this
    			log.warning("extra bytes at the end of 'head' table")
    			assert rest == b"\0\0"

    		# For timestamp fields, ignore the top four bytes.  Some fonts have
    		# bogus values there.  Since till 2038 those bytes only can be zero,
    		# ignore them.
    		#
    		# https://github.com/fonttools/fonttools/issues/99#issuecomment-66776810
    		for stamp in 'created', 'modified':
    			value = getattr(self, stamp)
    			if value > 0xFFFFFFFF:
    				log.warning("'%s' timestamp out of range; ignoring top bytes", stamp)
    				value &= 0xFFFFFFFF
    				setattr(self, stamp, value)
    			if value < 0x7C259DC0: # January 1, 1970 00:00:00
    				log.warning("'%s' timestamp seems very low; regarding as unix timestamp", stamp)
    				value += 0x7C259DC0
    				setattr(self, stamp, value)

    	def compile(self, ttFont):
    		if ttFont.recalcBBoxes:
    			# For TT-flavored fonts, xMin, yMin, xMax and yMax are set in table__m_a_x_p.recalc().
    			if 'CFF ' in ttFont:
    				topDict = ttFont['CFF '].cff.topDictIndex[0]
    				self.xMin, self.yMin, self.xMax, self.yMax = intRect(topDict.FontBBox)
    			elif 'CFF2' in ttFont:
    				topDict = ttFont['CFF2'].cff.topDictIndex[0]
    				charStrings = topDict.CharStrings
    				fontBBox = None
    				for charString in charStrings.values():
    					bounds = charString.calcBounds(charStrings)
    					if bounds is not None:
    						if fontBBox is not None:
    							fontBBox = unionRect(fontBBox, bounds)
    						else:
    							fontBBox = bounds
    				if fontBBox is not None:
    					self.xMin, self.yMin, self.xMax, self.yMax = intRect(fontBBox)
    		if ttFont.recalcTimestamp:
    			self.modified = timestampNow()
    		data = sstruct.pack(headFormat, self)
    		return data

    	def toXML(self, writer, ttFont):
    		writer.comment("Most of this table will be recalculated by the compiler")
    		writer.newline()
    		_, names, fixes = sstruct.getformat(headFormat)
    		for name in names:
    			value = getattr(self, name)
    			if name in fixes:
    				value = floatToFixedToStr(value, precisionBits=fixes[name])
    			elif name in ("created", "modified"):
    				value = timestampToString(value)
    			elif name in ("magicNumber", "checkSumAdjustment"):
    				if value < 0:
    					value = value + 0x100000000
    				value = hex(value)
    				if value[-1:] == "L":
    					value = value[:-1]
    			elif name in ("macStyle", "flags"):
    				value = num2binary(value, 16)
    			writer.simpletag(name, value=value)
    			writer.newline()

    	def fromXML(self, name, attrs, content, ttFont):
    		value = attrs["value"]
    		fixes = sstruct.getformat(headFormat)[2]
    		if name in fixes:
    			value = strToFixedToFloat(value, precisionBits=fixes[name])
    		elif name in ("created", "modified"):
    			value = timestampFromString(value)
    		elif name in ("macStyle", "flags"):
    			value = binary2num(value)
    		else:
    			value = safeEval(value)
    		setattr(self, name, value)