} // temporarily replace the abstract modifier with virtual protected virtual void CalculateCheckSum() { // This will need to be overridden for the 'head' table _calculatedChecksum = OTFile.CalcTableCheckSum(_parentFont.MemoryStream, _tableRecord.Offset, _tableRecord.Length); }
protected override void CalculateCheckSum() { /* The 'head' table requires special handling for calculating a checksum. The * process also involves the head.checksumAdjustment field. Both will be * calculated. * * From OT spec (v1.8.3) font file regarding TableRecord.checkSum for 'head': * To calculate the checkSum for the 'head' table which itself includes the * checkSumAdjustment entry for the entire font, do the following: * 1. Set the checkSumAdjustment to 0. * 2. Calculate the checksum for all the tables including the 'head' table * and enter that value into the table directory. * * NOTE: This wording is unclear and can be misleading. The TableRecord.checkSum * for 'head' is calculated using the modified 'head' data only, not the rest of * the file. * * From OT spec 'head' table regarding checkSumAdjustment: * To compute it: set it to 0, sum the entire font as uint32, * then store 0xB1B0AFBA - sum. * * If the font is used as a component in a font collection file, the value * of this field will be invalidated by changes to the file structure and * font table directory, and must be ignored. * * If in a TTC, ignore all that and just set both to 0. */ if (_parentFont.File.IsCollection) { _calculatedChecksum = 0; _calculatedCheckSumAdjustment = 0; return; } // get a copy of the byte array segment for the 'head' table byte[] fileData = _parentFont.MemoryStream.GetBuffer(); // ref, not copy! // make sure to get a four-byte-integral slice uint length = (_tableRecord.Length + 3U) & ~3U; byte[] headDataSegment = new byte[length]; Array.ConstrainedCopy(fileData, (int)_tableRecord.Offset, headDataSegment, 0, (int)length); // In the copy, clear the checkSumAdjustment field, bytes at relative offset 8 to 11 byte[] bytes = new byte[4] { 0, 0, 0, 0 }; bytes.CopyTo(headDataSegment, 8); // calculate the checksum for this modified 'head' copy -- that should match what's in TableRecord MemoryStream ms = new MemoryStream(headDataSegment, 0, headDataSegment.Length, true, true); _calculatedChecksum = OTFile.CalcTableCheckSum(ms, 0, length); // Now to calculate checkSumAdjustment: need to checksum the entire file with // head.checkSumAdjustment set to 0. Instead of copying the entire file, we // can compute checksum in steps: start with the file segment before the // 'head' table; then add onto that the modified 'head' copy; then add to // that the remainder of the file. // // NOTE: C# addition is left associative. We can't calculate three separate // checksums and then combine them. We need to start the calculation for the // second and third portions using the prior sum as the initial left operand. // get checksum for first file segment before the 'head' table // (note: head offset must be > 0) UInt32 sum = OTFile.CalcTableCheckSum(_parentFont.MemoryStream, 0, _tableRecord.Offset); // continue with the modified 'head' segment, passing sum as leftPriorSum sum = OTFile.CalcTableCheckSum(ms, 0, length, sum); // continue with the remainder of the file uint offsetAfterHead = _tableRecord.Offset + length; if (offsetAfterHead < _parentFont.File.Length) { sum = OTFile.CalcTableCheckSum(_parentFont.MemoryStream, offsetAfterHead, (uint)(_parentFont.File.Length - offsetAfterHead), sum); } // Now get 0xB1B0AFBA - sum unchecked { _calculatedCheckSumAdjustment = 0xB1B0AFBA - sum; } } // CalculateChecksum