PRIVATE int16 CopyOffsetDirectoryTables(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, TTFACC_FILEBUFFERINFO * pOutputBufferInfo, uint16 usFormat, uint32 * pulNewOutOffset ) { DIRECTORY *aDirectory; DIRECTORY Directory; OFFSET_TABLE OffsetTable; DTTF_HEADER DttfHeader; uint16 usnTables; uint16 usnNewTables; uint32 ulOffset; uint32 ulDttfOffset; uint16 usTableIdx; uint16 usBytesRead; uint16 usBytesWritten; uint32 ulBytesWritten; int16 errCode; ulDttfOffset = TTTableOffset( (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, DTTF_TAG); /* check to see if one there already */ if (ulDttfOffset != DIRECTORY_ERROR) { if ((errCode = ReadGeneric((TTFACC_FILEBUFFERINFO *) pInputBufferInfo, (uint8 *) &DttfHeader, SIZEOF_DTTF_HEADER, DTTF_HEADER_CONTROL, ulDttfOffset, &usBytesRead)) != NO_ERROR) return(errCode); if (DttfHeader.format != TTFDELTA_MERGE) /* only acceptable delta font at this time */ return(ERR_INVALID_DELTA_FORMAT); } /* read offset table and determine number of existing tables */ ulOffset = pInputBufferInfo->ulOffsetTableOffset; if ((errCode = ReadGeneric((TTFACC_FILEBUFFERINFO *) pInputBufferInfo, (uint8 *) &OffsetTable, SIZEOF_OFFSET_TABLE, OFFSET_TABLE_CONTROL, ulOffset, &usBytesRead)) != NO_ERROR) return(errCode); usnTables = OffsetTable.numTables; ulOffset += usBytesRead; /* Create a list of valid tables */ aDirectory = (DIRECTORY *) Mem_Alloc((usnTables + (ulDttfOffset == 0)) * sizeof(DIRECTORY)); /* one extra for possible private table */ if (aDirectory == NULL) return(ERR_MEM); /* sort directories by offset */ for ( usTableIdx = usnNewTables = 0; usTableIdx < usnTables; usTableIdx++ ) { errCode = ReadGeneric((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, (uint8 *) &Directory, SIZEOF_DIRECTORY, DIRECTORY_CONTROL, ulOffset, &usBytesRead); ulOffset += usBytesRead; if (errCode != NO_ERROR) { Mem_Free(aDirectory); return errCode; } if (usFormat == TTFDELTA_DELTA) /* need to get rid of some of the tables */ { switch(Directory.tag)/* only want to keep these */ { /* tables sent each time */ case HEAD_LONG_TAG: case MAXP_LONG_TAG: case HHEA_LONG_TAG: case VHEA_LONG_TAG: /* tables subsetted */ case CMAP_LONG_TAG: case GLYF_LONG_TAG: case EBLC_LONG_TAG: case EBDT_LONG_TAG: case BLOC_LONG_TAG: case BDAT_LONG_TAG: /* tables compacted */ case LTSH_LONG_TAG: case HMTX_LONG_TAG: case VMTX_LONG_TAG: case HDMX_LONG_TAG: case LOCA_LONG_TAG: /* private table - keep shell */ case DTTF_LONG_TAG: break; default: /* any others, just get rid of */ continue; /* don't copy this over */ } } /* empty out the entries */ aDirectory[ usnNewTables ].length = 0; aDirectory[ usnNewTables ].offset = DIRECTORY_ERROR; aDirectory[ usnNewTables ].tag = Directory.tag; /* don't worry about the checksum */ ++ usnNewTables; } /* add in dttf entry */ if (ulDttfOffset == 0 && usFormat == TTFDELTA_SUBSET1 || usFormat == TTFDELTA_DELTA) { aDirectory[ usnNewTables].length = 0; aDirectory[ usnNewTables].offset = DIRECTORY_ERROR; aDirectory[ usnNewTables].tag = DTTF_LONG_TAG; ++usnNewTables; SortByTag( aDirectory, usnNewTables ); /* to insert the dttf table */ } OffsetTable.numTables = usnNewTables; /* don't worry if other fields not ok, will be updated in compress tables */ ulOffset = pOutputBufferInfo->ulOffsetTableOffset; errCode = WriteGeneric( pOutputBufferInfo, (uint8 *) &OffsetTable, SIZEOF_OFFSET_TABLE, OFFSET_TABLE_CONTROL, ulOffset, &usBytesWritten); /* write out the new directory info to the output buffer */ ulOffset += usBytesWritten; if (errCode == NO_ERROR) { errCode = WriteGenericRepeat( pOutputBufferInfo, (uint8 *) aDirectory, DIRECTORY_CONTROL, ulOffset, &ulBytesWritten, usnNewTables, SIZEOF_DIRECTORY ); if (errCode == NO_ERROR) *pulNewOutOffset = ulOffset+ulBytesWritten; /* end of written to data */ } Mem_Free(aDirectory); return(errCode); }
int16 ModXmtxXhea( CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, TTFACC_FILEBUFFERINFO * pOutputBufferInfo, CONST uint8 *puchKeepGlyphList, CONST uint16 usGlyphListCount, CONST uint16 usDttfGlyphIndexCount, CONST uint16 usMaxGlyphIndexUsed, BOOL isHmtx, uint32 *pulNewOutOffset) { XHEA XHea; uint16 i,j; uint32 ulXmtxOffset; uint32 ulXheaOffset; uint32 ulCrntOffset; LONGXMETRIC ZeroLongMetric; LONGXMETRIC CurrLongMetric; LONGXMETRIC *LongMetricsArray; uint16 LongMetricSize; int16 errCode; uint16 usBytesRead; uint16 usBytesWritten; uint16 nNewLongMetrics; uint32 ulBytesWritten; const char * xmtx_tag; const char * xhea_tag; /* determine number of long metrics in hmtx table */ if (isHmtx) { xmtx_tag = HMTX_TAG; xhea_tag = HHEA_TAG; if ((ulXheaOffset = GetHHea( pOutputBufferInfo, (HHEA *) &XHea )) == 0L) { /* hasn't been copied yet */ if ((errCode = CopyTableOver(pOutputBufferInfo, pInputBufferInfo, xhea_tag, pulNewOutOffset)) != NO_ERROR) return ERR_INVALID_HHEA; if ((ulXheaOffset = GetHHea( pOutputBufferInfo, (HHEA *) &XHea )) == 0L) return ERR_MISSING_HHEA; /* required table */ } } else { xmtx_tag = VMTX_TAG; xhea_tag = VHEA_TAG; ulXheaOffset = TTTableOffset( (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, xhea_tag); ulXmtxOffset = TTTableOffset( (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, xmtx_tag); if (ulXheaOffset != DIRECTORY_ERROR && ulXmtxOffset == DIRECTORY_ERROR) /* this is bogus, get rid of the vhea table */ { MarkTableForDeletion(pOutputBufferInfo, xhea_tag); /* there is an entry in the output directory */ return (NO_ERROR); } if ((ulXheaOffset = GetVHea( pOutputBufferInfo, (VHEA *) &XHea )) == 0L) { if ((errCode = CopyTableOver(pOutputBufferInfo, pInputBufferInfo, xhea_tag, pulNewOutOffset)) != NO_ERROR) { if (errCode == ERR_FORMAT) return NO_ERROR; /* not required */ else return errCode; } if ((ulXheaOffset = GetVHea( pOutputBufferInfo, (VHEA *) &XHea )) == 0L) return ERR_MISSING_VHEA; /* */ } } if ((errCode = CopyTableOver(pOutputBufferInfo, pInputBufferInfo, xmtx_tag, pulNewOutOffset)) != NO_ERROR) return errCode; ulXmtxOffset = TTTableOffset( pOutputBufferInfo, xmtx_tag); if ((XHea.numLongMetrics == 0) || (XHea.numLongMetrics > usGlyphListCount)) return ERR_INVALID_HHEA_OR_VHEA; /* invalid values */ if (ulXmtxOffset == DIRECTORY_ERROR ) return ERR_MISSING_HMTX_OR_VMTX; /* required table */ ulCrntOffset = ulXmtxOffset; ZeroLongMetric.xsb = 0; ZeroLongMetric.advanceX = 0; LongMetricSize = GetGenericSize(LONGXMETRIC_CONTROL); if (usDttfGlyphIndexCount == 0) /* not trying to make a compact table, just subsetting */ { /* check to see if we will grow. We will grow with subsetting if our last good glyph index is beyond the current numLongMetrics */ if ((XHea.numLongMetrics != usGlyphListCount) && /* if longmetrics is the same as number of glyphs, table won't be growing */ /* need for zero based to 1 base + 1 for the dummy 0 entry */ (usMaxGlyphIndexUsed + 1 + 1 > XHea.numLongMetrics)) /* check if we may make the table grow */ return (ERR_WOULD_GROW); nNewLongMetrics = min(usGlyphListCount, usMaxGlyphIndexUsed + 1 + 1); /* + 1 again for dummy */ /* process all the Long metrics (and perhaps some short when we won't be modifying the table */ for (i = 0; i < nNewLongMetrics; ++i) { if (puchKeepGlyphList[i] == FALSE)/* else we don't want to keep this one, 0 metrics to write */ { if ((errCode = WriteGeneric( pOutputBufferInfo, (uint8 *)&ZeroLongMetric, SIZEOF_LONGXMETRIC, LONGXMETRIC_CONTROL, ulCrntOffset, &usBytesWritten)) != NO_ERROR) return (errCode); } ulCrntOffset += LongMetricSize; } /* write out short metrics of 0 for the rest of them*/ for (i = nNewLongMetrics; i < usGlyphListCount; ++i) { if ((errCode = WriteWord(pOutputBufferInfo, 0, ulCrntOffset)) != NO_ERROR) return errCode; ulCrntOffset += sizeof (uint16); } ulBytesWritten = ulCrntOffset - ulXmtxOffset; } else /* we want to make a compact table */ { /* now collapse the table if we are in Compact form for Subsetting and Delta fonts */ /* we will use an interrum table for simplification */ ulCrntOffset = ulXmtxOffset; LongMetricsArray = (LONGXMETRIC *)Mem_Alloc(sizeof(LONGXMETRIC) * usDttfGlyphIndexCount); if (LongMetricsArray == NULL) return ERR_MEM; nNewLongMetrics = 0; for (i = 0, j= 0; i < XHea.numLongMetrics && j < usDttfGlyphIndexCount && errCode == NO_ERROR; ++i) /* need to read and copy up the values */ { if (puchKeepGlyphList[i]) /* if we want to keep the glyph, or its the last special one */ { if ((errCode = ReadGeneric( pOutputBufferInfo, (uint8 *)&CurrLongMetric, SIZEOF_LONGXMETRIC, LONGXMETRIC_CONTROL, ulCrntOffset, &usBytesRead)) != NO_ERROR) break; LongMetricsArray[j] = CurrLongMetric; ++j; ++nNewLongMetrics; } else if (i == XHea.numLongMetrics-1) /* its that special dummy "last" one, need AW value */ { if ((errCode = ReadGeneric( pOutputBufferInfo, (uint8 *)&CurrLongMetric, SIZEOF_LONGXMETRIC, LONGXMETRIC_CONTROL, ulCrntOffset, &usBytesRead)) != NO_ERROR) break; ++nNewLongMetrics; /* we will need an extra one, but guarenteed to be <= XHea.numLongMetrics */ } ulCrntOffset += LongMetricSize; } if (errCode != NO_ERROR) { Mem_Free(LongMetricsArray); return errCode; } for (; i < usGlyphListCount && j < usDttfGlyphIndexCount; ++i) /* copy the xsb from the long metrics */ { if (puchKeepGlyphList[i]) { if ((errCode = ReadWord( pOutputBufferInfo, (uint16 *)&(CurrLongMetric.xsb), ulCrntOffset)) != NO_ERROR) break; LongMetricsArray[j] = CurrLongMetric; ++j; } ulCrntOffset += sizeof(uint16); } if (errCode != NO_ERROR) { Mem_Free(LongMetricsArray); return errCode; } if (j != usDttfGlyphIndexCount) { Mem_Free(LongMetricsArray); return ERR_GENERIC; } /* first write out the long metrics */ errCode = WriteGenericRepeat(pOutputBufferInfo,(uint8 *)LongMetricsArray, LONGXMETRIC_CONTROL, ulXmtxOffset,&ulBytesWritten, nNewLongMetrics, SIZEOF_LONGXMETRIC); /* then write out the short metrics */ if (errCode == NO_ERROR) { ulCrntOffset = ulXmtxOffset + ulBytesWritten; for (i = nNewLongMetrics; i < usDttfGlyphIndexCount; ++i) { if ((errCode = WriteWord( pOutputBufferInfo, LongMetricsArray[i].xsb, ulCrntOffset)) != NO_ERROR) break; ulCrntOffset += sizeof(uint16); } } Mem_Free(LongMetricsArray); if (errCode != NO_ERROR) return errCode; ulBytesWritten = ulCrntOffset - ulXmtxOffset; } /* write out our new, shorter length... cleanup comes later */ errCode = UpdateDirEntry( pOutputBufferInfo, xmtx_tag, ulBytesWritten ); if (errCode == NO_ERROR && nNewLongMetrics != XHea.numLongMetrics) { XHea.numLongMetrics = nNewLongMetrics; /* leave these alone if the hmtx table will remain the same */ if ((errCode = WriteGeneric( pOutputBufferInfo, (uint8 *) &XHea, SIZEOF_XHEA, XHEA_CONTROL, ulXheaOffset, &usBytesWritten )) != NO_ERROR) return (errCode); } *pulNewOutOffset = ulCrntOffset; return errCode; }
int16 ModGlyfLocaAndHead( CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, TTFACC_FILEBUFFERINFO * pOutputBufferInfo, uint8 *puchKeepGlyphList, uint16 usGlyphCount, uint32 *pCheckSumAdjustment, /* this is returned to be saved with a subset1 or delta format font */ uint32 *pulNewOutOffset) { uint16 i; uint16 usOffset; uint16 usIdxToLocFmt; uint16 usBytesWritten; uint32 ulBytesWritten; int16 errCode = NO_ERROR; uint32 * aulLoca; uint32 ulGlyphLength; uint32 ulOutLoca; uint32 ulGlyfOffset; uint32 ulOutGlyfOffset; uint32 ulOutGlyfDirectoryOffset; uint32 ulHeadOffset; uint32 ulOutLocaOffset; uint32 ulOutLocaDirectoryOffset; DIRECTORY LocaDirectory, GlyfDirectory; HEAD Head; /* allocate memory for and read loca table */ aulLoca = (uint32 *)Mem_Alloc( (usGlyphCount + 1) * sizeof( uint32 )); if ( aulLoca == NULL ) return ERR_MEM; if (GetLoca((TTFACC_FILEBUFFERINFO *)pInputBufferInfo, aulLoca, usGlyphCount + 1) == 0L) { Mem_Free(aulLoca); return ERR_INVALID_LOCA; } if ((ulHeadOffset = GetHead(pOutputBufferInfo, &Head)) == 0L) { /* copy over head table. will update below */ if ((errCode = CopyTableOver(pOutputBufferInfo, pInputBufferInfo, HEAD_TAG, pulNewOutOffset))!=NO_ERROR) { Mem_Free(aulLoca); return errCode; } ulHeadOffset = GetHead(pOutputBufferInfo, &Head); } ulOutLoca = 0L; ulGlyfOffset = TTTableOffset( (TTFACC_FILEBUFFERINFO *)pInputBufferInfo, GLYF_TAG ); if (ulGlyfOffset == DIRECTORY_ERROR) /* this should have been setup */ { Mem_Free(aulLoca); return ERR_MISSING_GLYF; } ulOutGlyfDirectoryOffset = GetTTDirectory( pOutputBufferInfo, GLYF_TAG, &GlyfDirectory); /* make sure there is a directory entry */ if (ulOutGlyfDirectoryOffset == DIRECTORY_ERROR) /* this should have been setup */ { Mem_Free(aulLoca); return ERR_MISSING_GLYF; } if (GlyfDirectory.offset == DIRECTORY_ERROR) { if ((errCode = ZeroLongWordAlign(pOutputBufferInfo, *pulNewOutOffset, pulNewOutOffset)) != NO_ERROR) { Mem_Free(aulLoca); return errCode; } GlyfDirectory.offset = *pulNewOutOffset; } ulOutGlyfOffset = GlyfDirectory.offset; /* go thru the glyf table, copying up the glyphs to be saved */ for ( i = 0; i < usGlyphCount; i++ ) { ulGlyphLength = 0L; if (puchKeepGlyphList[i]) /* we want to keep this one */ { /* copy existing glyph data to new location */ if ( aulLoca[ i ] < aulLoca[ i+1 ] ) ulGlyphLength = aulLoca[ i+1 ] - aulLoca[ i ]; if ( ulGlyphLength ) { if ((errCode = CopyBlockOver( pOutputBufferInfo, pInputBufferInfo, ulOutGlyfOffset + ulOutLoca, ulGlyfOffset + aulLoca[ i ], ulGlyphLength )) != NO_ERROR) break; } } assert((ulOutLoca & 1) != 1); aulLoca[ i ] = ulOutLoca; ulOutLoca += ulGlyphLength; if (ulOutLoca & 1) { /* the glyph offset is on an odd-byte boundry. get ready for next time */ if ((errCode = WriteByte( pOutputBufferInfo, 0, ulOutGlyfOffset + ulOutLoca)) != NO_ERROR) break; ++ulOutLoca; } } if (errCode == NO_ERROR) { /* The last loca entry is the end of the last glyph! */ *pulNewOutOffset += ulOutLoca; aulLoca[ usGlyphCount ] = ulOutLoca; GlyfDirectory.length = ulOutLoca; errCode = WriteGeneric( pOutputBufferInfo, (uint8 *)&GlyfDirectory, SIZEOF_DIRECTORY, DIRECTORY_CONTROL, ulOutGlyfDirectoryOffset, &usBytesWritten ); } if (errCode != NO_ERROR) { Mem_Free(aulLoca); return errCode; } /* write out the modified 'loca' table */ ulOutLocaDirectoryOffset = GetTTDirectory( pOutputBufferInfo, LOCA_TAG, &LocaDirectory); /* make sure there is a directory entry */ if (ulOutLocaDirectoryOffset == DIRECTORY_ERROR) /* this should have been setup */ { Mem_Free(aulLoca); return ERR_MISSING_LOCA; } if ((errCode = ZeroLongWordAlign(pOutputBufferInfo, *pulNewOutOffset, pulNewOutOffset)) != NO_ERROR) { Mem_Free(aulLoca); return errCode; } ulOutLocaOffset = LocaDirectory.offset = *pulNewOutOffset; /* where to write the loca */ /* Check to see what format to use */ if (ulOutLoca <= 0x1FFFC) /* maximum number stored here (0xFFFE * 2) Chosen as conservative value over 0xFFFF * 2 */ { usIdxToLocFmt = SHORT_OFFSETS; for ( i = 0; i <= usGlyphCount; i++ ) { assert((aulLoca[i] & 1) != 1); /* can't have this, would be truncated */ usOffset = (uint16) (aulLoca[ i ] / 2L); if ((errCode = WriteWord( pOutputBufferInfo, usOffset, ulOutLocaOffset + i*sizeof(uint16) )) != NO_ERROR) break; } ulOutLoca = (uint32) (usGlyphCount+1) * sizeof(uint16); } else { usIdxToLocFmt = LONG_OFFSETS; errCode = WriteGenericRepeat(pOutputBufferInfo, (uint8 *) aulLoca, LONG_CONTROL,ulOutLocaOffset,&ulBytesWritten,(uint16) (usGlyphCount+1), sizeof(uint32)); ulOutLoca = ulBytesWritten; } if (errCode == NO_ERROR) { /* update the length, etc. for the loca table as well */ LocaDirectory.length = ulOutLoca; *pulNewOutOffset += ulOutLoca; if ((errCode = WriteGeneric( pOutputBufferInfo, (uint8 *) &LocaDirectory, SIZEOF_DIRECTORY, DIRECTORY_CONTROL, ulOutLocaDirectoryOffset, &usBytesWritten )) == NO_ERROR) { *pCheckSumAdjustment = Head.checkSumAdjustment;/* for use by dttf table */ Head.checkSumAdjustment = 0L; /* needs to be 0 when setting the file checksum value */ Head.indexToLocFormat = usIdxToLocFmt; errCode = WriteGeneric( pOutputBufferInfo, (uint8 *) &Head, SIZEOF_HEAD, HEAD_CONTROL, ulHeadOffset, &usBytesWritten); } } /* clean up */ Mem_Free( aulLoca ); return errCode; }