コード例 #1
0
ファイル: automap.cpp プロジェクト: JianwenSun/cc
int16 MortAutoMap(TTFACC_FILEBUFFERINFO * pInputBufferInfo,   /* ttfacc info */
                  uint8 * pabKeepGlyphs, /* binary list of glyphs to keep - to be updated here */
                  uint16 usnGlyphs,    /* number of glyphs in list */
                  uint16 fKeepFlag)
{
    MORTBINSRCHHEADER MortBinSrchHeader;
    MORTLOOKUPSINGLE  MortLookup;
    uint16 nEntries;
    uint16 usBytesRead;
    uint32 ulOffset;
    uint32 ulLength;
    uint32 ulLastOffset;
    int16 errCode = NO_ERROR;

    ulOffset = TTTableOffset( pInputBufferInfo, MORT_TAG );
    ulLength = TTTableLength( pInputBufferInfo, MORT_TAG );
    ulLastOffset = ulOffset+ulLength;

    if (ulOffset == DIRECTORY_ERROR || ulLength == 0)    /* nothing to map, we're done */
        return NO_ERROR;

    ulOffset += GetGenericSize(MORTHEADER_CONTROL);     /* skip over mortheader */

    if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&MortBinSrchHeader, SIZEOF_MORTBINSRCHHEADER, MORTBINSRCHHEADER_CONTROL, ulOffset, &usBytesRead ) )!= NO_ERROR)
        return errCode;

    ulOffset += usBytesRead;

    for ( nEntries = MortBinSrchHeader.nEntries; nEntries > 0 && ulOffset < ulLastOffset; nEntries--)
    {
        if ((errCode = ReadGeneric( pInputBufferInfo, (uint8 *)&MortLookup, SIZEOF_MORTLOOKUPSINGLE, MORTLOOKUPSINGLE_CONTROL, ulOffset, &usBytesRead ) )!= NO_ERROR)
            return errCode;
        ulOffset += usBytesRead;

        if ( MortLookup.glyphid1 < usnGlyphs && pabKeepGlyphs[MortLookup.glyphid1] == fKeepFlag && MortLookup.glyphid2 < usnGlyphs && pabKeepGlyphs[MortLookup.glyphid2] == 0)
            pabKeepGlyphs[MortLookup.glyphid2] = (uint8)(fKeepFlag + 1); /* set this value too */
    }
    return NO_ERROR;
}
コード例 #2
0
ファイル: automap.cpp プロジェクト: JianwenSun/cc
int16 TTOAutoMap( TTFACC_FILEBUFFERINFO * pInputBufferInfo,   /* ttfacc info */
                  uint8 * pabKeepGlyphs, /* binary list of glyphs to keep - to be updated here */
                  uint16 usnGlyphs,    /* number of glyphs in list */
                  uint16 fKeepFlag) /* flag index (really contains a number) of what to set in the pabKeepGlyph list */
{
    GSUBHEADER GSUBHeader;
    GSUBLOOKUPLIST GSUBLookupList, *pGSUBLookupList = NULL;
    JSTFHEADER JSTFHeader;
    JSTFSCRIPTRECORD *ScriptRecordArray;
    JSTFSCRIPT JSTFScript;
    JSTFEXTENDERGLYPH JSTFExtenderGlyph;
    uint16 *GlyphIDArray;
    BASEHEADER BASEHeader;
    BASEAXIS BASEAxis;
    BASESCRIPTLIST BASEScriptList;
    BASESCRIPTRECORD BASEScriptRecord;
    BASESCRIPT BASEScript;
    BASEVALUES BASEValues;
    BASELANGSYSRECORD BASELangSysRecord;
    uint16 BASECoordOffset;
    uint16 AxisOffset;
    uint32 ulHeaderOffset;
    uint32 ulCurrentOffset;
    uint32 ulLangSysOffset;
    uint16 usMaxLookupCount;
    uint32 ulOffset;
    uint16 i, j, k;
    uint16 usBytesRead;
    uint32 ulBytesRead;
    int16 errCode = NO_ERROR;


    /* Process GSUB Table */
    while (1)  /* so we can break out on null offsets */
    {
        ulHeaderOffset = TTTableOffset( pInputBufferInfo, GSUB_TAG );

        if (ulHeaderOffset == 0)
            break;

        if ((errCode = ReadGeneric( pInputBufferInfo,   (uint8 *)&GSUBHeader, SIZEOF_GSUBHEADER, GSUBHEADER_CONTROL, ulHeaderOffset, &usBytesRead ) )!= NO_ERROR)
            return errCode;

        /* now read the max number of lookups, for allocation of the lookup list */

        if (GSUBHeader.LookupListOffset == 0)
            break;
        if ((errCode = ReadGeneric( pInputBufferInfo,   (uint8 *)&GSUBLookupList, SIZEOF_GSUBLOOKUPLIST, GSUBLOOKUPLIST_CONTROL, ulHeaderOffset + GSUBHeader.LookupListOffset, &usBytesRead) )!= NO_ERROR)
            return errCode;
        usMaxLookupCount = GSUBLookupList.LookupCount;

        if (usMaxLookupCount == 0)
            break;

        while (1) /* so we can break out and clean up on error */
            /* Now look at lookup table, and add to list from Context lookups */
        {
            GSUBLOOKUP GSUBLookup;
            uint16 *SubstTableOffsetArray = NULL;

            ulOffset = ulHeaderOffset + GSUBHeader.LookupListOffset;
            pGSUBLookupList = (GSUBLOOKUPLIST *)Mem_Alloc(SIZEOF_GSUBLOOKUPLIST + usMaxLookupCount * sizeof(uint16));
            if (pGSUBLookupList == NULL)
            {
                errCode = ERR_MEM;
                break;
            }
            /* read the first part */
            if ((errCode = ReadGeneric( pInputBufferInfo,   (uint8 *) pGSUBLookupList, SIZEOF_GSUBLOOKUPLIST, GSUBLOOKUPLIST_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
                break;
            /* now read the array */
            if ((errCode = ReadGenericRepeat( pInputBufferInfo,  (uint8 *) ((uint8 *)pGSUBLookupList + SIZEOF_GSUBLOOKUPLIST), WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usMaxLookupCount, sizeof(uint16)) )!= NO_ERROR)
                break;

            /* now make sure all the referenced glyphs are in the keep table */

            for (i = 0; i < usMaxLookupCount; ++i)
            {
                uint16 usSubTableCount;

                if (pGSUBLookupList->LookupTableOffsetArray[i] == 0)
                    continue;
                ulOffset = ulHeaderOffset +
                           GSUBHeader.LookupListOffset +
                           pGSUBLookupList->LookupTableOffsetArray[i];
                if ((errCode = ReadGeneric( pInputBufferInfo,  (uint8 *)&GSUBLookup, SIZEOF_GSUBLOOKUP, GSUBLOOKUP_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
                    break;
                if (GSUBLookup.LookupType == GSUBContextLookupType)  /* not looking for context lookups */
                    continue;
                usSubTableCount = GSUBLookup.SubTableCount;
                SubstTableOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usSubTableCount);
                if (SubstTableOffsetArray == NULL)
                {
                    errCode = ERR_MEM;
                    break;
                }
                if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *) SubstTableOffsetArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usSubTableCount, sizeof(uint16)) )!= NO_ERROR)
                    break;

                for (j = 0; j < usSubTableCount; ++j)
                {
                    uint16 Format;

                    if (SubstTableOffsetArray[j] == 0)
                        continue;
                    ulOffset = ulHeaderOffset +
                               GSUBHeader.LookupListOffset +
                               pGSUBLookupList->LookupTableOffsetArray[i] +
                               SubstTableOffsetArray[j];
                    if ((errCode = ReadWord( pInputBufferInfo, &Format, ulOffset) )!= NO_ERROR)
                        break;
                    switch(GSUBLookup.LookupType)
                    {
                    case GSUBSingleLookupType:
                    {
                        switch    (Format)
                        {
                        case 1:
                        {
                            GSUBSINGLESUBSTFORMAT1 GSUBSubstTable;

                            if ((errCode = ReadGeneric( pInputBufferInfo,  (uint8 *)&GSUBSubstTable, SIZEOF_GSUBSINGLESUBSTFORMAT1, GSUBSINGLESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )== NO_ERROR)
                                errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , (uint16 *) &(GSUBSubstTable.DeltaGlyphID), GSUBLookup.LookupType, Format);
                            break;
                        }
                        case 2:
                        {
                            GSUBSINGLESUBSTFORMAT2 GSUBSubstTable;
                            uint16 usGlyphCount;
                            uint16 *pGlyphIDArray = NULL;

                            if ((errCode = ReadGeneric( pInputBufferInfo,  (uint8 *)&GSUBSubstTable, SIZEOF_GSUBSINGLESUBSTFORMAT2, GSUBSINGLESUBSTFORMAT2_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
                                break;
                            usGlyphCount = GSUBSubstTable.GlyphCount;
                            pGlyphIDArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usGlyphCount);
                            if (pGlyphIDArray == NULL)
                            {
                                errCode = ERR_MEM;
                                break;
                            }
                            if ((errCode = ReadGenericRepeat( pInputBufferInfo,  (uint8 *)pGlyphIDArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usGlyphCount, sizeof(uint16)) )== NO_ERROR)
                                errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pGlyphIDArray, GSUBLookup.LookupType, Format);
                            Mem_Free(pGlyphIDArray);
                            break;
                        }

                        default:
                            errCode = ERR_INVALID_GSUB;
                            break;
                        }
                        break;
                    }
                    case GSUBMultipleLookupType:
                    {
                        GSUBMULTIPLESUBSTFORMAT1 GSUBSubstTable;
                        uint16 usCount;
                        uint16 *pOffsetArray = NULL;

                        if (Format != 1)
                            break;
                        if ((errCode = ReadGeneric( pInputBufferInfo,  (uint8 *)&GSUBSubstTable, SIZEOF_GSUBMULTIPLESUBSTFORMAT1, GSUBMULTIPLESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
                            break;
                        usCount = GSUBSubstTable.SequenceCount;
                        pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount);
                        if (pOffsetArray == NULL)
                        {
                            errCode = ERR_MEM;
                            break;
                        }
                        if ((errCode = ReadGenericRepeat( pInputBufferInfo,  (uint8 *)pOffsetArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usCount, sizeof(uint16)) )== NO_ERROR)
                            errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, GSUBLookup.LookupType, Format);
                        Mem_Free(pOffsetArray);
                        break;
                    }
                    case GSUBAlternateLookupType:
                    {
                        GSUBALTERNATESUBSTFORMAT1 GSUBSubstTable;
                        uint16 usCount;
                        uint16 *pOffsetArray = NULL;

                        if (Format != 1)
                            break;
                        if ((errCode = ReadGeneric( pInputBufferInfo,  (uint8 *)&GSUBSubstTable, SIZEOF_GSUBALTERNATESUBSTFORMAT1, GSUBALTERNATESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
                            break;
                        usCount = GSUBSubstTable.AlternateSetCount;
                        pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount);
                        if (pOffsetArray == NULL)
                        {
                            errCode = ERR_MEM;
                            break;
                        }
                        if ((errCode = ReadGenericRepeat( pInputBufferInfo,  (uint8 *)pOffsetArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usCount, sizeof(uint16)) )== NO_ERROR)
                            errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, GSUBLookup.LookupType, Format);
                        Mem_Free(pOffsetArray);
                        break;
                    }
                    case GSUBLigatureLookupType:
                    {
                        GSUBLIGATURESUBSTFORMAT1 GSUBSubstTable;
                        uint16 usCount;
                        uint16 *pOffsetArray = NULL;

                        if (Format != 1)
                            break;
                        if ((errCode = ReadGeneric( pInputBufferInfo,  (uint8 *)&GSUBSubstTable, SIZEOF_GSUBLIGATURESUBSTFORMAT1, GSUBLIGATURESUBSTFORMAT1_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
                            break;
                        usCount = GSUBSubstTable.LigatureSetCount;
                        pOffsetArray = (uint16 *)Mem_Alloc(sizeof(uint16) * usCount);
                        if (pOffsetArray == NULL)
                        {
                            errCode = ERR_MEM;
                            break;
                        }
                        if ((errCode = ReadGenericRepeat( pInputBufferInfo,  (uint8 *)pOffsetArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, usCount, sizeof(uint16)) )== NO_ERROR)
                            errCode = UpdateKeepWithCoverage( pInputBufferInfo, pabKeepGlyphs, usnGlyphs, fKeepFlag, ulOffset, GSUBSubstTable.CoverageOffset , pOffsetArray, GSUBLookup.LookupType, Format);
                        Mem_Free(pOffsetArray);
                        break;
                    }
                    default:
                        break;
                    }
                    if (errCode != NO_ERROR)
                        break;

                }
                Mem_Free(SubstTableOffsetArray);
                if (errCode != NO_ERROR)
                    break;
            }
            break; /* artificial while for error conditions */
        }
        Mem_Free(pGSUBLookupList);
        break;
    }

    if (errCode != NO_ERROR)
        return errCode;
    /* Process JSTF Table */
    while (1) /* so we can break out on NULL offsets */
    {
        ulHeaderOffset = TTTableOffset( pInputBufferInfo, JSTF_TAG );

        if (ulHeaderOffset == 0)
            break;

        if ((errCode = ReadGeneric( pInputBufferInfo,   (uint8 *)&JSTFHeader, SIZEOF_JSTFHEADER, JSTFHEADER_CONTROL, ulHeaderOffset, &usBytesRead ) )!= NO_ERROR)
            break;
        ScriptRecordArray = (JSTFSCRIPTRECORD *)Mem_Alloc(SIZEOF_JSTFSCRIPTRECORD * JSTFHeader.ScriptCount);
        if (ScriptRecordArray == NULL)
        {
            errCode = ERR_MEM;
            break;
        }

        ulOffset = ulHeaderOffset;
        if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)ScriptRecordArray, JSTFSCRIPTRECORD_CONTROL, ulOffset + usBytesRead, & ulBytesRead, JSTFHeader.ScriptCount, SIZEOF_JSTFSCRIPTRECORD ) )!= NO_ERROR)
            break;

        for (i = 0 ; i < JSTFHeader.ScriptCount; ++i)
        {
            if (ScriptRecordArray[i].JstfScriptOffset == 0)
                continue;
            ulOffset = ulHeaderOffset + ScriptRecordArray[i].JstfScriptOffset;
            if ((errCode = ReadGeneric( pInputBufferInfo,  (uint8 *)&JSTFScript, SIZEOF_JSTFSCRIPT, JSTFSCRIPT_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
                break;
            if (JSTFScript.ExtenderGlyphOffset == 0)
                continue;
            ulOffset = ulOffset = ulHeaderOffset + ScriptRecordArray[i].JstfScriptOffset + JSTFScript.ExtenderGlyphOffset;

            if ((errCode = ReadGeneric( pInputBufferInfo,  (uint8 *)&JSTFExtenderGlyph, SIZEOF_JSTFEXTENDERGLYPH, JSTFEXTENDERGLYPH_CONTROL, ulOffset, &usBytesRead) )!= NO_ERROR)
                break;

            GlyphIDArray = (uint16 *)Mem_Alloc((sizeof(uint16) * JSTFExtenderGlyph.ExtenderGlyphCount));
            if (GlyphIDArray == NULL)
            {
                errCode = ERR_MEM;
                break;
            }
            if ((errCode = ReadGenericRepeat( pInputBufferInfo, (uint8 *)GlyphIDArray, WORD_CONTROL, ulOffset + usBytesRead, &ulBytesRead, JSTFExtenderGlyph.ExtenderGlyphCount, sizeof(uint16)) )== NO_ERROR)
            {
                for (j = 0; j < JSTFExtenderGlyph.ExtenderGlyphCount; ++j)
                {
                    if (GlyphIDArray[j] < usnGlyphs && pabKeepGlyphs[GlyphIDArray[j]] == 0)
                        pabKeepGlyphs[GlyphIDArray[j]] =  (uint8)(fKeepFlag + 1);
                }
            }
            Mem_Free(GlyphIDArray);
            if (errCode != NO_ERROR)
                break;
        }
        Mem_Free(ScriptRecordArray);
        break;
    }
    if (errCode != NO_ERROR)
        return errCode;
    /* Process BASE Table */
    while (1)
    {
        ulHeaderOffset = TTTableOffset( pInputBufferInfo, BASE_TAG );

        if (ulHeaderOffset == 0)
            break;

        if ((errCode = ReadGeneric( pInputBufferInfo,   (uint8 *)&BASEHeader, SIZEOF_BASEHEADER, BASEHEADER_CONTROL, ulHeaderOffset, &usBytesRead ) )!= NO_ERROR)
            break;

        AxisOffset = BASEHeader.HorizAxisOffset;
        for (i = 0; i < 2; ++i, AxisOffset = BASEHeader.VertAxisOffset)  /* process the 2 axis */
        {
            if (AxisOffset == 0)
                continue;
            ulOffset = ulHeaderOffset + AxisOffset;
            if ((errCode = ReadGeneric( pInputBufferInfo,   (uint8 *)&BASEAxis, SIZEOF_BASEAXIS, BASEAXIS_CONTROL, ulOffset, &usBytesRead ) )!= NO_ERROR)
                break;
            if (BASEAxis.BaseScriptListOffset == 0)
                continue;
            ulOffset = ulHeaderOffset + AxisOffset + BASEAxis.BaseScriptListOffset;
            if ((errCode = ReadGeneric( pInputBufferInfo,   (uint8 *)&BASEScriptList, SIZEOF_BASESCRIPTLIST, BASESCRIPTLIST_CONTROL, ulOffset, &usBytesRead ) )!= NO_ERROR)
                break;
            ulCurrentOffset = ulOffset + usBytesRead;
            for (j = 0; j < BASEScriptList.BaseScriptCount; ++j)
            {
                uint32 ulLocalOffset;

                if ((errCode = ReadGeneric( pInputBufferInfo,   (uint8 *)&BASEScriptRecord, SIZEOF_BASESCRIPTRECORD, BASESCRIPTRECORD_CONTROL, ulCurrentOffset, &usBytesRead ) )!= NO_ERROR)
                    break;
                ulCurrentOffset += usBytesRead;
                if (BASEScriptRecord.BaseScriptOffset == 0)
                    continue;

                if ((errCode = ReadGeneric( pInputBufferInfo,   (uint8 *)&BASEScript, SIZEOF_BASESCRIPT, BASESCRIPT_CONTROL, ulOffset + BASEScriptRecord.BaseScriptOffset, &usBytesRead ) )!= NO_ERROR)
                    break;

                ulLangSysOffset = ulOffset + BASEScriptRecord.BaseScriptOffset + usBytesRead;

                /* PROCESS BaseValuesOffset */
                if (BASEScript.BaseValuesOffset    != 0)
                {
                    ulLocalOffset = ulOffset + BASEScriptRecord.BaseScriptOffset + BASEScript.BaseValuesOffset ;

                    if ((errCode = ReadGeneric( pInputBufferInfo,   (uint8 *)&BASEValues, SIZEOF_BASEVALUES, BASEVALUES_CONTROL, ulLocalOffset, &usBytesRead ) )!= NO_ERROR)
                        break;
                    ulLocalOffset += usBytesRead;
                    for (k = 0; k < BASEValues.BaseCoordCount; ++k)
                    {
                        if ((errCode = ReadWord( pInputBufferInfo,  &BASECoordOffset, ulLocalOffset ) )!= NO_ERROR)
                            break;
                        ulLocalOffset += sizeof(uint16);
                        if ((errCode = ProcessBaseCoord( pInputBufferInfo, ulOffset + BASEScriptRecord.BaseScriptOffset + BASEScript.BaseValuesOffset + BASECoordOffset, pabKeepGlyphs, usnGlyphs, fKeepFlag))!= NO_ERROR)
                            break;
                    }
                    if (errCode != NO_ERROR)
                        break;
                }
                /* Process MinMaxOffset */
                if (BASEScript.MinMaxOffset != 0)
                {
                    ulLocalOffset = ulOffset + BASEScriptRecord.BaseScriptOffset + BASEScript.MinMaxOffset ;
                    if ((errCode = ProcessMinMax( pInputBufferInfo, ulLocalOffset, pabKeepGlyphs, usnGlyphs, fKeepFlag))!= NO_ERROR)
                        break;
                }
                /* Process BaseLangSysRecordArray */
                for (k = 0; k < BASEScript.BaseLangSysCount; ++k)
                {
                    if ((errCode = ReadGeneric( pInputBufferInfo,  (uint8 *)&BASELangSysRecord, SIZEOF_BASELANGSYSRECORD, BASELANGSYSRECORD_CONTROL, ulLangSysOffset, &usBytesRead ) )!= NO_ERROR)
                        break;
                    ulLangSysOffset += usBytesRead;
                    if (BASELangSysRecord.MinMaxOffset != 0)
                        if ((errCode = ProcessMinMax( pInputBufferInfo, ulOffset + BASEScriptRecord.BaseScriptOffset + BASELangSysRecord.MinMaxOffset, pabKeepGlyphs, usnGlyphs, fKeepFlag))!= NO_ERROR)
                            break;
                }
                if (errCode != NO_ERROR)
                    break;
            }
            if (errCode != NO_ERROR)
                break;
        }
        break;
    }
    return errCode;

}
コード例 #3
0
ファイル: modtable.cpp プロジェクト: JianwenSun/cc
int16 ModVDMX(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, 
              TTFACC_FILEBUFFERINFO * pOutputBufferInfo,
              CONST uint16 usFormat,
              uint32 *pulNewOutOffset)
{
VDMX Vdmx;
uint32 ulSrcOffset; /* offset to Src VDMX table */
uint32 ulSrcLength; /* length of Src VDMX table */
uint32 ulDestOffset; /* offset to Dest VDMX table */
uint32 ulDestLength; /* length of Dest VDMX table */
uint32 ulSrcOffsetRatios;   /* absolute offset to Ratios in Src file */
uint32 ulSrcOffsetOffsets;  /* absolute offset to Offsets in Src file */
uint32 ulSrcOffsetGroups;   /* absolute offset to Groups in Src file */
uint32 ulDestOffsetRatios;  /* absolute offset to Ratios in Dest file */
uint32 ulDestOffsetOffsets; /* absolute offset to Offsets in Dest file */
uint32 ulDestOffsetGroups;  /* absolute offset to Groups in Dest file */
uint16 usCurrGroupSrcOffset; /* relative offset from beginning of VDMX table */
uint16 usCurrGroupDestOffset; /* relative offset from beginning of VDMX table */
uint32 ulCurrGroupDestOffset=0; /* relative offset from beginning of VDMX table - long value */
uint16 usGroupDestOffset; /* relative offset from beginning of VDMX table, local copy for writing */
uint16 ----cRatioIndex,usDestRatioIndex;
uint16 i;
uint16 usBytesRead;
uint16 usBytesWritten;
uint32 ulBytesRead;
int16 errCode=NO_ERROR;
VDMXRatio *SrcRatioArray=NULL;
int8 *KeepSrcRatioArray = NULL;   /* parallel array to SrcRatioArray */
VDMXGroup GroupHeader;
uint8 * pGroupBuffer=NULL;
uint32 ulGroupBufferLength; /* total length of the Group Buffer (from source file) */
uint32 ulGroupLength; /* length of individual group to be read */
uint16 usGroupCount = 0; 
uint16 usKeepRatioCount = 0;
uint16 usRatioSize;
uint16 xRatio, yRatio; /* for reducing the ratios */
int16 Found1to1; 
GROUPOFFSETRECORDKEEPER keeper; 
TTFACC_FILEBUFFERINFO * pUnCONSTInputBufferInfo;

    if (usFormat == TTFDELTA_DELTA)  /* only formats for which this is not valid */
    {
        MarkTableForDeletion(pOutputBufferInfo, VDMX_TAG);
        return errCode;
    }

    pUnCONSTInputBufferInfo = (TTFACC_FILEBUFFERINFO *) pInputBufferInfo; /* used for Read functions ONLY. Not for Write */
/* get input buffer information */
    ulSrcOffset = TTTableOffset( pUnCONSTInputBufferInfo, VDMX_TAG );
    if ( ulSrcOffset == 0L )
        return NO_ERROR;
    ulSrcLength = TTTableLength( pUnCONSTInputBufferInfo, VDMX_TAG );
    if ( ulSrcLength == 0L )
    {
        MarkTableForDeletion(pOutputBufferInfo, VDMX_TAG);
        return NO_ERROR;
    }
    /* get output buffer information */
    if ((errCode = ZeroLongWordAlign(pOutputBufferInfo, *pulNewOutOffset, &ulDestOffset)) != NO_ERROR)
        return errCode;

    if ((errCode = ReadGeneric( pUnCONSTInputBufferInfo, (uint8 *) &Vdmx, SIZEOF_VDMX, VDMX_CONTROL, ulSrcOffset, &usBytesRead )) != NO_ERROR)
        return errCode;
    if (Vdmx.numRatios == 0)
    {
        MarkTableForDeletion(pOutputBufferInfo, VDMX_TAG);
        return NO_ERROR;
    }


    ulSrcOffsetRatios = ulSrcOffset + usBytesRead;
    ulSrcOffsetOffsets = ulSrcOffsetRatios + GetGenericSize(VDMXRATIO_CONTROL) * Vdmx.numRatios;
    ulSrcOffsetGroups = ulSrcOffsetOffsets + sizeof(uint16) * Vdmx.numRatios;
    memset(&keeper, 0, sizeof(keeper));

    SrcRatioArray = (VDMXRatio *)Mem_Alloc(Vdmx.numRatios * sizeof(VDMXRatio));
    if (SrcRatioArray == NULL)
        errCode = ERR_MEM;
    else
    {
        KeepSrcRatioArray = (int8 *)Mem_Alloc(Vdmx.numRatios * sizeof(int8));
        if (KeepSrcRatioArray == NULL)
            errCode = ERR_MEM;
        else
            errCode = ReadGenericRepeat(pUnCONSTInputBufferInfo, (uint8 *) SrcRatioArray, VDMXRATIO_CONTROL, ulSrcOffsetRatios, &ulBytesRead, Vdmx.numRatios, SIZEOF_VDMXRATIO );
    }

    while (errCode == NO_ERROR)     /* while is so we can break out. Only go once through */
    {
        Found1to1 = FALSE;
        for (i = 0; i < Vdmx.numRatios ; ++i)    /* keep all 1:1 aspect ratios */
        {
            KeepSrcRatioArray[i] = 1; /* assume we'll keep it */
            xRatio = SrcRatioArray[i].xRatio;
            yRatio = SrcRatioArray[i].yStartRatio;
            ReduceRatio(&xRatio,&yRatio);
            if (xRatio == yRatio)
            {
                if (SrcRatioArray[i].xRatio == 0)   /* anything after 0:0 is ignored */
                {
                    if (!Found1to1) /* need to keep this one */
                        ++usKeepRatioCount;
                    break;
                }
                if (Found1to1)  /* already have one */
                    KeepSrcRatioArray[i] = 0;  /* don't keep this one */
                else
                {
                    Found1to1 = TRUE;
                    ++usKeepRatioCount;
                }
            }
            else if (xRatio == EGA_X_RATIO && yRatio == EGA_Y_RATIO)
                KeepSrcRatioArray[i] = 0;  /* don't keep this one */
            else
                ++usKeepRatioCount;
        }

        if ((usKeepRatioCount == 0) || (usKeepRatioCount == Vdmx.numRatios))
        {                       /* don't change a thing */
            Mem_Free(SrcRatioArray);
            Mem_Free(KeepSrcRatioArray);
            return CopyTableOver(pOutputBufferInfo, pInputBufferInfo, VDMX_TAG, pulNewOutOffset);
        }
        ulDestOffsetRatios = ulDestOffset + usBytesRead;
        /* figure out offset for the Offset array */
        ulDestOffsetOffsets = ulDestOffsetRatios + GetGenericSize(VDMXRATIO_CONTROL) * usKeepRatioCount;
        ulDestOffsetGroups = ulDestOffsetOffsets + sizeof(uint16) * usKeepRatioCount;
        usRatioSize = GetGenericSize(VDMXRATIO_CONTROL);
        ulCurrGroupDestOffset = ulDestOffsetGroups - ulDestOffset; /* calculate offset from start of VDMX table */
        if ((errCode = InitGroupOffsetArray(&keeper,usKeepRatioCount)) != NO_ERROR)  /* initialize structure to track offset re-use */ 
            break;
        ulGroupBufferLength = ulSrcLength - (ulSrcOffsetGroups - ulSrcOffset);  /* calculate the length of the group section */
        pGroupBuffer = (uint8 *)Mem_Alloc(ulGroupBufferLength); /* allocate buffer the size of the group buffer */
        if (pGroupBuffer == NULL)
        {
            errCode = ERR_MEM;
            break;
        }
        
        for (----cRatioIndex = usDestRatioIndex = 0; ----cRatioIndex < Vdmx.numRatios && usDestRatioIndex < usKeepRatioCount; ++----cRatioIndex)     /* keep all 1:1 aspect ratios */
        {
            if (KeepSrcRatioArray[----cRatioIndex] == 1)
            {
                /* write out the Ratio to the proper location */
                if ((errCode = WriteGeneric(pOutputBufferInfo, (uint8 *) &(SrcRatioArray[----cRatioIndex]), SIZEOF_VDMXRATIO, VDMXRATIO_CONTROL, ulDestOffsetRatios + (usDestRatioIndex * usRatioSize), &usBytesWritten)) != NO_ERROR)
                    break;
                /* now read the offset to the group */
                if ((errCode = ReadWord(pUnCONSTInputBufferInfo, &usCurrGroupSrcOffset, ulSrcOffsetOffsets + (----cRatioIndex * sizeof(uint16)) )) != NO_ERROR)
                    break;
                /* check if offset already used */
                if ((usGroupDestOffset = LookupGroupOffset(&keeper, usCurrGroupSrcOffset)) == 0)  /* not there already */
                {
                    if (ulCurrGroupDestOffset > USHRT_MAX)  /* check if will fit in unsigned short */
                    {
                        errCode = ERR_INVALID_VDMX;
                        break;
                    }
                    usCurrGroupDestOffset = (uint16) ulCurrGroupDestOffset;  /* already checked if in range */
                    /* need to register the old and new group offsets */
                    if ((errCode = RecordGroupOffset(&keeper, usCurrGroupSrcOffset, usCurrGroupDestOffset)) != NO_ERROR)
                        break;

                    usGroupDestOffset = usCurrGroupDestOffset;
                    /* need to copy the group data over */
                    if ((errCode = ReadGeneric(pUnCONSTInputBufferInfo, (uint8 *) &GroupHeader, SIZEOF_VDMXGROUP, VDMXGROUP_CONTROL, ulSrcOffset + usCurrGroupSrcOffset, &usBytesRead)) != NO_ERROR)
                        break;
 
                    ulGroupLength =  usBytesRead + (GroupHeader.recs * GetGenericSize(VDMXVTABLE_CONTROL));
                    /* read the group data into a buffer */
                    if (ulGroupLength > ulGroupBufferLength)
                    {
                        errCode = ERR_INVALID_VDMX; /* error in data! */
                        break;
                    }
                    if ((errCode = ReadBytes(pUnCONSTInputBufferInfo, (uint8 *) pGroupBuffer, ulSrcOffset + usCurrGroupSrcOffset, ulGroupLength)) != NO_ERROR)
                        break;
                    /* and write them to the output buffer */
                    if ((errCode = WriteBytes(pOutputBufferInfo, (uint8 *) pGroupBuffer, ulDestOffset + usCurrGroupDestOffset, ulGroupLength)) != NO_ERROR)
                        break;
                    ++usGroupCount;
                    /* increment our CurrGroupDestOffset value for next time around */
                    ulCurrGroupDestOffset = usCurrGroupDestOffset + ulGroupLength;
                }
                /* now write out that relative offset value */
                if ((errCode = WriteWord(pOutputBufferInfo, usGroupDestOffset, ulDestOffsetOffsets + (usDestRatioIndex * sizeof(uint16)))) != NO_ERROR)
                    break;

                ++usDestRatioIndex; /* increment in dest array */
            }
        }
        break; /* out of while */
    }
    if (errCode == NO_ERROR)
    {
        Vdmx.numRatios = usKeepRatioCount;
        Vdmx.numRecs = usGroupCount;
        errCode = WriteGeneric( pOutputBufferInfo, (uint8 *) &Vdmx, SIZEOF_VDMX, VDMX_CONTROL, ulDestOffset, &usBytesWritten );
    }
    
    if (errCode == NO_ERROR)
    {
        ulDestLength = ulCurrGroupDestOffset; /* this is the size of the table */
        errCode = UpdateDirEntryAll( pOutputBufferInfo, VDMX_TAG, ulDestLength, ulDestOffset );
        *pulNewOutOffset = ulDestOffset + ulDestLength;
    }
 
    FreeGroupOffsetArray(&keeper);  /* free up structure to track offset re-use */ 

    Mem_Free(pGroupBuffer);

    Mem_Free(KeepSrcRatioArray);
    Mem_Free(SrcRatioArray);
    return errCode;
}
コード例 #4
0
ファイル: modtable.cpp プロジェクト: JianwenSun/cc
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;
}
コード例 #5
0
ファイル: modtable.cpp プロジェクト: JianwenSun/cc
int16 ModKern(  CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, TTFACC_FILEBUFFERINFO * pOutputBufferInfo, 
              CONST uint8 *puchKeepGlyphList, 
              CONST uint16 usGlyphListCount,
              CONST uint16 usFormat,
              uint32 *pulNewOutOffset)
{
uint32 ulOffset;
uint32 ulSourceOffset;
uint32 ulTargetOffset;
KERN_HEADER KernHeader;
KERN_SUB_HEADER  KernSubHeader;
uint16 i;
uint16 usSubtableLength;
uint16 usBytesRead;
int16 errCode = NO_ERROR;
    /* read kern table header */

    
    if (usFormat == TTFDELTA_DELTA) /* only formats for which this is valid */
    {
        MarkTableForDeletion(pOutputBufferInfo, KERN_TAG);
        return NO_ERROR;
    }
    if ((errCode = CopyTableOver(pOutputBufferInfo, pInputBufferInfo, KERN_TAG, pulNewOutOffset)) != NO_ERROR)  
    {
        if (errCode == ERR_FORMAT)
            return NO_ERROR;    /* not required */
        return errCode;
    }

    if (usFormat == TTFDELTA_SUBSET1)   /* need to keep the full kern table as we will send only once */
        return NO_ERROR;

    ulOffset = TTTableOffset( pOutputBufferInfo, KERN_TAG );
    if ( ulOffset == 0L )
        return ERR_GENERIC;    /* should have been copied over */
    if ((errCode = ReadGeneric( pOutputBufferInfo, (uint8 *) &KernHeader, SIZEOF_KERN_HEADER, KERN_HEADER_CONTROL, ulOffset, &usBytesRead )) != NO_ERROR)
        return errCode;

    /* read each subtable.  If it is a format 0 subtable, remove
    kern pairs involving deleted glyphs.  Otherwise, copy
    the table down to its new location */

    ulSourceOffset = ulOffset + usBytesRead;
    ulTargetOffset = ulSourceOffset;
    for ( i = 0; i < KernHeader.nTables; i++ )
    {
        /* read subtable header */
        if ((errCode = ReadGeneric( pOutputBufferInfo, (uint8 *) &KernSubHeader, SIZEOF_KERN_SUB_HEADER, KERN_SUB_HEADER_CONTROL, ulSourceOffset, &usBytesRead )) != NO_ERROR)
            return errCode;

        /* copy data to new location to cover any gaps left by shortening the previous
        format 0 subtable. Nothing happens first time around. */

        if ((errCode = CopyBlock( pOutputBufferInfo, ulTargetOffset, ulSourceOffset, KernSubHeader.length )) != NO_ERROR)
            return errCode;
        ulSourceOffset += KernSubHeader.length;

        /* if subtable is format 0, shorten it by deleting kern pairs
        involving deleted glyphs */

        if ( KernSubHeader.format == 0 )
        {
            if ((errCode = AdjustKernFormat0( pOutputBufferInfo, puchKeepGlyphList, usGlyphListCount, KernSubHeader, ulTargetOffset, usBytesRead, &usSubtableLength)) != NO_ERROR)
                return errCode;
            ulTargetOffset += usSubtableLength;
        }
        else
            ulTargetOffset += KernSubHeader.length;
    }

    /* Write out revised table length */
    if (ulTargetOffset == ulOffset + GetGenericSize( KERN_HEADER_CONTROL )) /* no Kern data written */
        MarkTableForDeletion(pOutputBufferInfo, KERN_TAG);
    else
        errCode = UpdateDirEntry( pOutputBufferInfo, KERN_TAG, ulTargetOffset - ulOffset );
    *pulNewOutOffset = ulTargetOffset;
    return errCode;
}
コード例 #6
0
ファイル: modtable.cpp プロジェクト: JianwenSun/cc
int16 ModName( CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo, 
              TTFACC_FILEBUFFERINFO * pOutputBufferInfo, 
              CONST uint16 usLanguage,
              CONST uint16 usFormat,
              uint32 *pulNewOutOffset)
{
PNAMERECORD pNameRecordArray; /* internal representation of NameRecord - from ttftable.h */
uint16 NameRecordCount;
int16 errCode = NO_ERROR;
uint16 i;
uint16 bKeptMSPlatformRecord = FALSE; /* has a MS Platform record been kept? */
uint16 bDeleteStrings = FALSE; /* should we delete strings when writing out table? */
uint32 ulBytesWritten = 0;
uint32 ulNameOffset;
uint32 ulNameLength;
TTFACC_FILEBUFFERINFO NameTableBufferInfo; /* needed by WriteNameRecords */

    if (usFormat == TTFDELTA_DELTA) /* only formats for which this is not valid */
    {
        MarkTableForDeletion(pOutputBufferInfo, NAME_TAG);
        return errCode;
    }
    if ((errCode = CopyTableOver(pOutputBufferInfo, pInputBufferInfo, NAME_TAG, pulNewOutOffset))!= NO_ERROR)
        return errCode; /*  required */

    ulNameOffset = TTTableOffset( pOutputBufferInfo, NAME_TAG);
    ulNameLength = TTTableLength( pOutputBufferInfo, NAME_TAG);

/* Get info about Name table */

    if ((errCode = ReadAllocNameRecords(pOutputBufferInfo, &pNameRecordArray, &NameRecordCount, Mem_Alloc, Mem_Free)) != NO_ERROR)
        return errCode;
    
    if (usLanguage != TTFSUB_LANG_KEEP_ALL)
    {
        for (i = 0; i < NameRecordCount; ++i)
        {
            if (pNameRecordArray[i].platformID == TTFSUB_MS_PLATFORMID) 
            {
                if (pNameRecordArray[i].languageID == usLanguage) /* we want to keep this one */
                    bKeptMSPlatformRecord = TRUE;
                else  /* we don't want it */
                {
                    pNameRecordArray[i].bDeleteString = TRUE;  /* mark it for deletion */
                    bDeleteStrings = TRUE;
                }
            }
        }
        if (bDeleteStrings && !bKeptMSPlatformRecord)    /* if we asked to keep a language that wasn't found, don't delete others */
            bDeleteStrings = FALSE;
    }
    /* now fake up a bufferinfo so that WriteNameRecords will write to the actual file buffer */
    InitFileBufferInfo(&NameTableBufferInfo, pOutputBufferInfo->puchBuffer + ulNameOffset, ulNameLength, NULL /*cant reallocate!*/);

    errCode = WriteNameRecords(&NameTableBufferInfo, pNameRecordArray, NameRecordCount, bDeleteStrings, TRUE, &ulBytesWritten);
    FreeNameRecords(pNameRecordArray, NameRecordCount, Mem_Free);

    if (errCode == NO_ERROR)
    {
        *pulNewOutOffset = ulNameOffset + ulBytesWritten;
        UpdateDirEntry(pOutputBufferInfo, NAME_TAG, ulBytesWritten);
    }
    else /* ran out of room? restore it */
    {
        *pulNewOutOffset = ulNameOffset;
        errCode = CopyTableOver(pOutputBufferInfo, pInputBufferInfo, NAME_TAG, pulNewOutOffset);
    }

    return errCode;
}
コード例 #7
0
int16 ComputeMaxPStats( TTFACC_FILEBUFFERINFO * pInputBufferInfo, 
            uint16 *  pusMaxContours,
            uint16 *  pusMaxPoints,
            uint16 *  pusMaxCompositeContours,
            uint16 *  pusMaxCompositePoints,
            uint16 *  pusMaxInstructions,
            uint16 *  pusMaxComponentElements,
            uint16 *  pusMaxComponentDepth,
            uint16 *  pausComponents, 
            uint16 usnMaxComponents)
{
HEAD Head;
int16    snContours;
uint16   usnPoints;
uint16   usnInstructions;
uint16   usGlyphIdx;
uint16   prepLength;
uint16   fpgmLength;
uint16   usnCompElements;
uint16   usnCompDepth;
uint16 usGlyphCount;
uint32 ulLocaOffset;
uint32 ulGlyfOffset;
int16 errCode;
BOOL bStatus;

    *pusMaxContours          = 0;
    *pusMaxPoints            = 0;
    *pusMaxInstructions      = 0;
    *pusMaxCompositeContours = 0;
    *pusMaxCompositePoints   = 0;
    *pusMaxComponentElements = 0;
    *pusMaxComponentDepth    = 0;

    /* Build a Loca table that will be used to decide if a glyph has contours
    or not. There are g_usnGlyphs+1 Loca entries. */

    usGlyphCount = GetNumGlyphs(pInputBufferInfo);
    if (usGlyphCount == 0)
        return ERR_NO_GLYPHS;

    ulLocaOffset = TTTableOffset(pInputBufferInfo, LOCA_TAG);
    if ( ulLocaOffset == 0L )
        return ERR_MISSING_LOCA;

    ulGlyfOffset = TTTableOffset(pInputBufferInfo, GLYF_TAG);
    if ( ulGlyfOffset == 0L )
        return ERR_MISSING_GLYF;

    if (!GetHead(pInputBufferInfo, &Head))   /* for Head.indexToLocFormat */
        return ERR_MISSING_HEAD;

    for ( usGlyphIdx = 0; usGlyphIdx < usGlyphCount; usGlyphIdx++ )
    {
    /* get statistics on the glyph component */

        if ((errCode = GetGlyphStats(pInputBufferInfo, usGlyphIdx, &snContours, &usnPoints, &usnInstructions,
                    Head.indexToLocFormat, ulLocaOffset, ulGlyfOffset, &bStatus)) != NO_ERROR)
            return errCode;
        if (bStatus == FALSE) 
            continue;
        
        /* remember maxes for simple glyph */

        if ( snContours >= 0 )
        {
            *pusMaxContours     = max( *pusMaxContours, (uint16) snContours );
            *pusMaxPoints       = max( *pusMaxPoints, usnPoints );
            *pusMaxInstructions = max( *pusMaxInstructions, usnInstructions );
        }
        /* remember maxes for composite glyph */
        else if (snContours == -1)
        {
        /* start with usnInstructions at 0 for MAX test in fn call... */
            usnCompElements = usnCompDepth = usnInstructions = 0;
            GetCompositeGlyphStats( pInputBufferInfo, usGlyphIdx, &snContours, &usnPoints,
                 &usnInstructions, &usnCompElements, &usnCompDepth,
                 Head.indexToLocFormat, ulLocaOffset, ulGlyfOffset, pausComponents, usnMaxComponents );
            *pusMaxCompositeContours = max( *pusMaxCompositeContours, (uint16) snContours );
            *pusMaxCompositePoints   = max( *pusMaxCompositePoints, usnPoints );
            *pusMaxInstructions      = max( *pusMaxInstructions, usnInstructions );
            *pusMaxComponentElements = max( *pusMaxComponentElements, usnCompElements );
            *pusMaxComponentDepth    = max( *pusMaxComponentDepth, usnCompDepth );
        }
        else 
            return ERR_INVALID_GLYF;  /* what is it? */
    }

    prepLength = (uint16) TTTableLength( pInputBufferInfo, PREP_TAG );
    fpgmLength = (uint16) TTTableLength( pInputBufferInfo, FPGM_TAG );
    *pusMaxInstructions = max( max( prepLength, fpgmLength), *pusMaxInstructions );

    return NO_ERROR;
}
コード例 #8
0
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);
}
コード例 #9
0
ファイル: modcmap.cpp プロジェクト: JianwenSun/cc
int16 ModCmap(CONST_TTFACC_FILEBUFFERINFO * pInputBufferInfo,
                TTFACC_FILEBUFFERINFO * pOutputBufferInfo,
                uint8 *puchKeepGlyphList, /* glyphs to keep - boolean */
                uint16 usGlyphCount,  /* count of puchKeepGlyphList */
                uint16 * pOS2MinChr,     /* for setting in the OS/2 table */
                uint16 * pOS2MaxChr,     /* for setting in the OS/2 table */
                uint32 *pulNewOutOffset)
{
FORMAT4_SEGMENTS *NewFormat4Segments = NULL;   /* used to create a Segments    array for format 4 subtables */
FORMAT12_GROUPS     *NewFormat12Groups = NULL;    
uint16 usnSegment;
GLYPH_ID *NewFormat4GlyphIdArray = NULL; /* used to create a GlyphID array for format 4 subtables */
uint16 snFormat4GlyphIdArray;
CMAP_FORMAT4 CmapFormat4;
CMAP_FORMAT12 CmapFormat12;
CMAP_TABLELOC *pCmapTableLoc=NULL;
uint16 usSubTableCount;
CMAP_SUBHEADER_GEN CmapSubHeader;
PCHAR_GLYPH_MAP_LIST pCharGlyphMapList = NULL;    /* sorted list of character codes to keep and their glyph indices */
uint16 usnCharGlyphMapListCount= 0;    /* length of pCharGlyphMapList array */
PCHAR_GLYPH_MAP_LIST_EX pCharGlyphMapListEx = NULL;    /* sorted list of character codes to keep and their glyph indices */
uint32 ulnCharGlyphMapListCount= 0;                    /* length of pCharGlyphMapListEx array */
CMAPOFFSETRECORDKEEPER CmapSubtableKeeper;
uint32 ulCmapOffset;
uint32 ulCmapLength;
uint32 ulCmapNewLength;
uint32 ulCmapSubTableDirOffset;
uint32 ulCmapSubtableNewOffset;
uint32 ulBytesWritten;
uint16 i;
int16 errCode= NO_ERROR;
uint16 usBytesRead;

    if ((errCode = CopyTableOver(pOutputBufferInfo, pInputBufferInfo, CMAP_TAG, pulNewOutOffset)) != NO_ERROR)
        return errCode;

    ulCmapOffset = TTTableOffset( pOutputBufferInfo, CMAP_TAG );
    ulCmapLength = TTTableLength( pOutputBufferInfo, CMAP_TAG);
    *pOS2MinChr = 0;
    *pOS2MaxChr = 0;
    if (ulCmapOffset == 0L || ulCmapLength == 0L)
        return ERR_INVALID_CMAP;  /* huh?*/

    usSubTableCount = GetCmapSubtableCount(pOutputBufferInfo, ulCmapOffset);
    pCmapTableLoc = (CMAP_TABLELOC *)Mem_Alloc(SIZEOF_CMAP_TABLELOC * usSubTableCount);
    if (pCmapTableLoc == NULL)
        return ERR_MEM;
    ulCmapSubTableDirOffset  = ulCmapOffset + GetGenericSize( CMAP_HEADER_CONTROL );

    if (InitCmapOffsetArray(&CmapSubtableKeeper, usSubTableCount) != NO_ERROR)
    {
        return ERR_MEM;
    }
    
    for (i = 0; i < usSubTableCount; ++i)
    {
        /* read the cmap directory entry */
         if ((errCode = ReadGeneric(pOutputBufferInfo, (uint8 *) &(pCmapTableLoc[i]), SIZEOF_CMAP_TABLELOC, CMAP_TABLELOC_CONTROL, ulCmapSubTableDirOffset, &usBytesRead)) != NO_ERROR)
            break; 
        ulCmapSubTableDirOffset += usBytesRead;  /* for next time around */

        /* Check to see if this subtable is shared, and has been modified already */
        if ((ulCmapSubtableNewOffset = LookupCmapOffset(&CmapSubtableKeeper, pCmapTableLoc[i].offset)) != 0)
        {
            pCmapTableLoc[i].offset = ulCmapSubtableNewOffset;
            continue;
        }
        /* now read the CmapSub Header, to determine the format */
         if ((errCode = ReadCmapLength(pOutputBufferInfo, &CmapSubHeader, ulCmapOffset + pCmapTableLoc[i].offset, &usBytesRead)) != NO_ERROR)
            break; 

        /* Will subset: Format 0, Format 4 ,Format 6 and Format 12 Cmap Subtables */
        /* Otherwise, leave them alone */

        if (CmapSubHeader.format == FORMAT0_CMAP_FORMAT)
        {
            if ((errCode = ModMacStandardCmap(pOutputBufferInfo, ulCmapOffset + pCmapTableLoc[i].offset + usBytesRead, puchKeepGlyphList, usGlyphCount)) != NO_ERROR)
                break;
        }
        else if (CmapSubHeader.format == FORMAT6_CMAP_FORMAT)
        {
            if ((errCode = ModMacTrimmedCmap(pOutputBufferInfo, ulCmapOffset + pCmapTableLoc[i].offset, puchKeepGlyphList, usGlyphCount)) != NO_ERROR)
                break;
        }
        else if (CmapSubHeader.format == FORMAT4_CMAP_FORMAT)
        {
        
            /* process Format 4 Cmap Subtable */
             /*need to come up with a CharCodeList, from the puchKeepGlyphList  */
            errCode = ReadAllocFormat4CharGlyphMapList(pOutputBufferInfo, pCmapTableLoc[i].platformID, pCmapTableLoc[i].encodingID, puchKeepGlyphList, usGlyphCount, &pCharGlyphMapList, &usnCharGlyphMapListCount); 

            if (errCode != NO_ERROR)
                break;

            NewFormat4Segments = (FORMAT4_SEGMENTS *) Mem_Alloc( (usnCharGlyphMapListCount+1) * SIZEOF_FORMAT4_SEGMENTS ); /* add one for the extra dummy segment */
            NewFormat4GlyphIdArray = (GLYPH_ID *) Mem_Alloc( usnCharGlyphMapListCount * sizeof( *NewFormat4GlyphIdArray ) );

            if ( NewFormat4Segments == NULL || NewFormat4GlyphIdArray == NULL )
            {
                errCode = ERR_MEM;
                break;
            }

            /* compute new format 4 data */

            ComputeFormat4CmapData( &CmapFormat4, NewFormat4Segments, &usnSegment, 
                                    NewFormat4GlyphIdArray, &snFormat4GlyphIdArray, pCharGlyphMapList, usnCharGlyphMapListCount );


            /* Donald, if you don't care if the Cmap subtable grows, you could comment out the next line */
            
            if (CmapFormat4.length <= CmapSubHeader.length) /* if the new length is smaller than the old, we can write it in the old place */
            {
                if (pCmapTableLoc[i].platformID == MS_PLATFORMID)  /* only applies to this platform */
                {
                    *pOS2MinChr = pCharGlyphMapList[0].usCharCode;
                    *pOS2MaxChr = pCharGlyphMapList[usnCharGlyphMapListCount-1].usCharCode;
                }
                errCode = WriteOutFormat4CmapData( pOutputBufferInfo, &CmapFormat4, NewFormat4Segments, NewFormat4GlyphIdArray, usnSegment,
                             snFormat4GlyphIdArray, ulCmapOffset + pCmapTableLoc[i].offset, &ulBytesWritten );
            }
            /* else: leave cmap subtable alone */

            /* clean up */

            Mem_Free(NewFormat4Segments);
            Mem_Free(NewFormat4GlyphIdArray );
            FreeFormat4CharCodes(pCharGlyphMapList);
            
            NewFormat4Segments = NULL;
            NewFormat4GlyphIdArray = NULL;
            pCharGlyphMapList = NULL;
        }
        else if (CmapSubHeader.format == FORMAT12_CMAP_FORMAT)
        {
            uint32 ulnGroups = 0;

            /*need to come up with a CharCodeList, from the puchKeepGlyphList  */
            errCode = ReadAllocFormat12CharGlyphMapList(pOutputBufferInfo, ulCmapOffset + pCmapTableLoc[i].offset, puchKeepGlyphList, usGlyphCount, &pCharGlyphMapListEx, &ulnCharGlyphMapListCount); 
            if (errCode != NO_ERROR)
                break;

            NewFormat12Groups = (FORMAT12_GROUPS *) Mem_Alloc( (ulnCharGlyphMapListCount) * SIZEOF_FORMAT12_GROUPS );
            if ( NewFormat12Groups == NULL)
            {
                errCode = ERR_MEM;
                break;
            }

            /* compute new format 12 data */
            ComputeFormat12CmapData( &CmapFormat12, NewFormat12Groups, &ulnGroups, pCharGlyphMapListEx, ulnCharGlyphMapListCount );

            /* Donald, if you don't care if the Cmap subtable grows, you could comment out the next line */
            if (CmapFormat12.length <= CmapSubHeader.length) /* if the new length is smaller than the old, we can write it in the old place */
            {
                if (pCmapTableLoc[i].platformID == MS_PLATFORMID)  /* only applies to this platform */
                {
                    *pOS2MinChr = (uint16)pCharGlyphMapListEx[0].ulCharCode;
                    *pOS2MaxChr = (uint16)pCharGlyphMapListEx[ulnCharGlyphMapListCount-1].ulCharCode;
                }
                errCode = WriteOutFormat12CmapData( pOutputBufferInfo, &CmapFormat12, NewFormat12Groups, ulnGroups,
                             ulCmapOffset + pCmapTableLoc[i].offset, &ulBytesWritten );
            }
            /* else: leave cmap subtable alone */

            /* clean up */
            Mem_Free(NewFormat12Groups);
            FreeFormat12CharCodes(pCharGlyphMapListEx);
            
            NewFormat12Groups = NULL;
            pCharGlyphMapListEx = NULL;
        }
        RecordCmapOffset(&CmapSubtableKeeper, pCmapTableLoc[i].offset, pCmapTableLoc[i].offset); /* record the new offset (didn't change) */
    }
    /* now need to compress out empty bytes from ends of Cmap Subtables */
    if (errCode == NO_ERROR)
    {
        errCode = CompressCmapSubTables(pOutputBufferInfo, pCmapTableLoc, usSubTableCount, ulCmapOffset, ulCmapSubTableDirOffset, ulCmapLength, &ulCmapNewLength);
        *pulNewOutOffset = ulCmapOffset + ulCmapNewLength; /* hand back to caller */
    }
    else /* these weren't taken care of yet (necessarily) */
    {
        Mem_Free(NewFormat4Segments); /* may be non-null */
        Mem_Free(NewFormat4GlyphIdArray );
        FreeFormat4CharCodes(pCharGlyphMapList);
        if (errCode == ERR_WOULD_GROW)  /* fragmentation has caused a larger cmap table, copy table again */
        {
            *pulNewOutOffset = ulCmapOffset; /* reset */
            errCode = CopyTableOver(pOutputBufferInfo, pInputBufferInfo, CMAP_TAG, pulNewOutOffset);
        }
    }
    Mem_Free(pCmapTableLoc);
    FreeCmapOffsetArray(&CmapSubtableKeeper);

    return errCode;

} /* ModCmap() */
コード例 #10
0
ファイル: modglyf.cpp プロジェクト: JianwenSun/cc
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;

}