static byte[] get_TTF_digest(OTFile f) { OTFont fn = f.GetFont(0); Table_DSIG tDSIG = (Table_DSIG)fn.GetTable("DSIG"); DirectoryEntry deDSIG = null; // sort table by offset Dictionary <uint, int> offsetlookup = new Dictionary <uint, int>(); var list = new List <uint>(); for (ushort i = 0; i < fn.GetNumTables(); i++) { DirectoryEntry de = fn.GetDirectoryEntry(i); offsetlookup.Add(de.offset, i); list.Add(de.offset); if ((string)de.tag == "DSIG") { deDSIG = de; } } list.Sort(); // New offset table var old_ot = fn.GetOffsetTable(); OffsetTable ot = new OffsetTable(old_ot.sfntVersion, (ushort)(old_ot.numTables - 1)); for (ushort i = 0; i < fn.GetNumTables(); i++) { DirectoryEntry oldde = fn.GetDirectoryEntry(i); if ((string)oldde.tag != "DSIG") { DirectoryEntry de = new DirectoryEntry(oldde); de.offset -= 16; // one less entry if (de.offset > deDSIG.offset) { de.offset -= tDSIG.GetBuffer().GetPaddedLength(); } ot.DirectoryEntries.Add(de); } } hash.TransformBlock(ot.m_buf.GetBuffer(), 0, (int)ot.m_buf.GetLength(), ot.m_buf.GetBuffer(), 0); for (int i = 0; i < ot.DirectoryEntries.Count; i++) { DirectoryEntry de = (DirectoryEntry)ot.DirectoryEntries[i]; hash.TransformBlock(de.m_buf.GetBuffer(), 0, (int)de.m_buf.GetLength(), de.m_buf.GetBuffer(), 0); } Table_head headTable = (Table_head)fn.GetTable("head"); // calculate the checksum uint sum = 0; sum += ot.CalcOffsetTableChecksum(); sum += ot.CalcDirectoryEntriesChecksum(); foreach (var key in list) { OTTable table = fn.GetTable((ushort)offsetlookup[key]); if ((string)table.GetTag() != "DSIG") { sum += table.CalcChecksum(); } } Table_head.head_cache headCache = (Table_head.head_cache)headTable.GetCache(); // set the checkSumAdujustment field headCache.checkSumAdjustment = 0xb1b0afba - sum; Table_head newHead = (Table_head)headCache.GenerateTable(); foreach (var key in list) { OTTable table = fn.GetTable((ushort)offsetlookup[key]); if ((string)table.GetTag() == "head") { table = newHead; } if ((string)table.GetTag() != "DSIG") { hash.TransformBlock(table.m_bufTable.GetBuffer(), 0, (int)table.GetBuffer().GetPaddedLength(), table.m_bufTable.GetBuffer(), 0); } } byte[] usFlag = { 0, 1 }; hash.TransformFinalBlock(usFlag, 0, 2); return(hash.Hash); }
/***************** * protected methods */ /***************** * public methods */ //meant to avoid code repetition (is called from OTFontVal too) public bool ValidateTable(OTTable table, Validator v, DirectoryEntry de, OTFontVal fontOwner) { String tname = GetTableManager().GetUnaliasedTableName(de.tag); bool bRet = true; // verify the checksum value from the directory entry matches the checksum for the table if (!(tname == "DSIG" && IsCollection())) { uint calcChecksum = 0; if (table != null) { calcChecksum = table.CalcChecksum(); } if (de.checkSum != calcChecksum) { string s = "table '" + de.tag + "', calc: 0x" + calcChecksum.ToString("x8") + ", font: 0x" + de.checkSum.ToString("x8"); v.Error(T.T_NULL, E._DE_E_ChecksumError, de.tag, s); bRet = false; } } // verify that table has pad bytes set to zero if (table != null) { uint nBytes = 0; try { nBytes = GetNumPadBytesAfterTable(table); } catch (Exception e) { v.ApplicationError(T.T_NULL, E._Table_E_Exception, de.tag, "GetNumPadBytesAfterTable: " + e.Message); bRet = false; } bool bPadBytesZero = true; if (nBytes != 0) { long PadFilePos = table.GetBuffer().GetFilePos() + table.GetBuffer().GetLength(); byte[] padbuf = ReadBytes(PadFilePos, nBytes); for (int iByte = 0; iByte < padbuf.Length; iByte++) { if (padbuf[iByte] != 0) { bPadBytesZero = false; break; } } } if (bPadBytesZero == false) { v.Warning(T.T_NULL, W._DE_W_PadBytesNotZero, de.tag, "after " + de.tag + " table"); } } // ask the table object to validate its data if (!(tname == "DSIG" && IsCollection())) { v.OnTableValidationEvent(de, true); } if (table != null) { if (v.TestTable(de.tag)) // don't test deselected tables { try { ITableValidate valtable = (ITableValidate)table; bRet &= valtable.Validate(v, fontOwner); } catch (InvalidCastException e) { v.ApplicationError(T.T_NULL, E._Table_E_Exception, table.m_tag, e.ToString()); bRet = false; } } else { v.Info(I._Table_I_NotSelected, de.tag); } } else { if (de.length == 0) { // check if it's a known OT table type since zero length private tables seem allowable if (TableManager.IsKnownOTTableType(de.tag)) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The directory entry length is zero"); bRet = false; } } else if (de.offset == 0) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The directory entry offset is zero"); bRet = false; } else if (de.offset > GetFileLength()) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The table offset points past end of file"); bRet = false; } else if (de.offset + de.length > GetFileLength()) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The table extends past end of file"); bRet = false; } else { v.Error(E._Table_E_Invalid, de.tag); bRet = false; } } if (!(tname == "DSIG" && IsCollection())) { v.OnTableValidationEvent(de, false); } return(bRet); }
static byte[] get_TTC_digest(OTFile f) { TTCHeader ttc = f.GetTTCHeader(); uint back_shift = 12; //if ( ttc.version == 0x00020000 ) back_shift = 0; TTCHBuffer ttcb = new TTCHBuffer(12 + ttc.DirectoryCount * 4 + 12 - back_shift); // write the TTC header ttcb.FillUint32MBO((uint)ttc.TTCTag); ttcb.FillUint32MBO(ttc.version); ttcb.FillUint32MBO(ttc.DirectoryCount); for (int i = 0; i < f.GetNumFonts(); i++) { ttcb.FillUint32MBO((uint)ttc.DirectoryOffsets[i] - back_shift); } //if ( ttc.version == 0x00020000 ) { ttcb.FillUint32MBO(0); ttcb.FillUint32MBO(0); ttcb.FillUint32MBO(0); } uint Position = (uint)ttcb.buffer.Length; hash.TransformBlock(ttcb.buffer, 0, ttcb.buffer.Length, ttcb.buffer, 0); // build an array of offset tables OffsetTable[] otArr = new OffsetTable[f.GetNumFonts()]; for (uint iFont = 0; iFont < f.GetNumFonts(); iFont++) { otArr[iFont] = new OffsetTable(new OTFixed(1, 0), f.GetFont(iFont).GetNumTables()); for (ushort i = 0; i < f.GetFont(iFont).GetNumTables(); i++) { DirectoryEntry old = f.GetFont(iFont).GetDirectoryEntry(i); DirectoryEntry de = new DirectoryEntry(old); de.offset -= back_shift; otArr[iFont].DirectoryEntries.Add(de); } } if ((uint)ttc.DirectoryOffsets[(int)f.GetNumFonts() - 1] < f.GetFont(0).GetDirectoryEntry(0).offset) { // assume directory-contiguous for (uint iFont = 0; iFont < f.GetNumFonts(); iFont++) { // write the offset table hash.TransformBlock(otArr[iFont].m_buf.GetBuffer(), 0, (int)otArr[iFont].m_buf.GetLength(), otArr[iFont].m_buf.GetBuffer(), 0); Position += otArr[iFont].m_buf.GetLength(); // write the directory entries for (int i = 0; i < f.GetFont(iFont).GetNumTables(); i++) { DirectoryEntry de = (DirectoryEntry)otArr[iFont].DirectoryEntries[i]; hash.TransformBlock(de.m_buf.GetBuffer(), 0, (int)de.m_buf.GetLength(), de.m_buf.GetBuffer(), 0); Position += de.m_buf.GetLength(); } } } // write out each font uint max_offset = 0; uint max_padded_length = 0; uint PrevPos = 0; for (uint iFont = 0; iFont < f.GetNumFonts(); iFont++) { ushort numTables = f.GetFont(iFont).GetNumTables(); if ((uint)ttc.DirectoryOffsets[(int)f.GetNumFonts() - 1] > f.GetFont(0).GetDirectoryEntry(0).offset) { // assume font-contiguous // write the offset table hash.TransformBlock(otArr[iFont].m_buf.GetBuffer(), 0, (int)otArr[iFont].m_buf.GetLength(), otArr[iFont].m_buf.GetBuffer(), 0); Position += otArr[iFont].m_buf.GetLength(); // write the directory entries for (int i = 0; i < numTables; i++) { DirectoryEntry de = (DirectoryEntry)otArr[iFont].DirectoryEntries[i]; hash.TransformBlock(de.m_buf.GetBuffer(), 0, (int)de.m_buf.GetLength(), de.m_buf.GetBuffer(), 0); Position += de.m_buf.GetLength(); } } // write out each table unless a shared version has been written for (ushort i = 0; i < numTables; i++) { DirectoryEntry de = (DirectoryEntry)otArr[iFont].DirectoryEntries[i]; if (de.offset > max_offset) { max_offset = de.offset; max_padded_length = f.GetFont(iFont).GetTable(de.tag).GetBuffer().GetPaddedLength(); } if (PrevPos < de.offset) //crude { OTTable table = f.GetFont(iFont).GetTable(de.tag); hash.TransformBlock(table.m_bufTable.GetBuffer(), 0, (int)table.GetBuffer().GetPaddedLength(), table.m_bufTable.GetBuffer(), 0); Position += table.GetBuffer().GetPaddedLength(); PrevPos = de.offset; } } } if (max_offset + max_padded_length - Position != 0) { throw new NotImplementedException("Unusual TTC Directory Layout"); } byte[] usFlag = { 0, 1 }; hash.TransformFinalBlock(usFlag, 0, 2); return(hash.Hash); }