include/sal/log-areas.dox            |    1 
 vcl/source/font/PhysicalFontFace.cxx |   53 ++++----
 vcl/source/fontsubset/cff.cxx        |  215 +++++++++++++++++++++--------------
 3 files changed, 161 insertions(+), 108 deletions(-)

New commits:
commit 56050d1b891c11730c2bbda8e252947a2856da57
Author:     Khaled Hosny <[email protected]>
AuthorDate: Sun Mar 8 23:22:12 2026 +0200
Commit:     Khaled Hosny <[email protected]>
CommitDate: Mon Mar 9 11:21:24 2026 +0100

    Shuffle code around to avoid creating a cmap table that we will not use
    
    In the CFF case we will use the bare CFF font, so no need to waste time
    creating a cmap table we will throw away any way.
    
    Change-Id: I5e2e6adb1743d82b1f4084da8570f1f65922cf86
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201229
    Tested-by: Jenkins
    Reviewed-by: Khaled Hosny <[email protected]>

diff --git a/vcl/source/font/PhysicalFontFace.cxx 
b/vcl/source/font/PhysicalFontFace.cxx
index b98764270b7c..b0ed50a8797a 100644
--- a/vcl/source/font/PhysicalFontFace.cxx
+++ b/vcl/source/font/PhysicalFontFace.cxx
@@ -545,13 +545,16 @@ bool 
PhysicalFontFace::CreateFontSubset(std::vector<sal_uInt8>& rOutBuffer,
                                              Point(XUnits(nUPEM, xMax), 
XUnits(nUPEM, yMax)));
     }
 
-    hb_blob_t* pSubsetBlob = nullptr;
-    comphelper::ScopeGuard aBuilderBlobGuard([&]() { 
hb_blob_destroy(pSubsetBlob); });
-
-    // HarfBuzz creates a Unicode cmap, but we need a fake cmap based on 
pEncoding,
-    // so we use face builder construct a new face based in the subset table,
-    // and create a new cmap table and add it to the new face.
+    hb_blob_t* pCFFBlob = hb_face_reference_table(pSubsetFace, HB_TAG('C', 
'F', 'F', ' '));
+    comphelper::ScopeGuard aCFFBlobGuard([&]() { hb_blob_destroy(pCFFBlob); });
+    if (pCFFBlob == hb_blob_get_empty())
     {
+        // This is not a font with CFF table, so we will create a TTF font 
subset.
+        rInfo.m_nFontType = FontType::SFNT_TTF;
+
+        // HarfBuzz creates a Unicode cmap, but we need a fake cmap based on 
pEncoding,
+        // so we use face builder construct a new face based in the subset 
table,
+        // and create a new cmap table and add it to the new face.
         hb_face_t* pBuilderFace = hb_face_builder_create();
         comphelper::ScopeGuard aBuilderFaceGuard([&]() { 
hb_face_destroy(pBuilderFace); });
         unsigned int nSubsetTableCount = hb_face_get_table_tags(pSubsetFace, 
0, nullptr, nullptr);
@@ -597,12 +600,18 @@ bool 
PhysicalFontFace::CreateFontSubset(std::vector<sal_uInt8>& rOutBuffer,
         hb_face_builder_add_table(pBuilderFace, HB_TAG('c', 'm', 'a', 'p'), 
pCmapBlob);
         hb_blob_destroy(pCmapBlob);
 
-        pSubsetBlob = hb_face_reference_blob(pBuilderFace);
-    }
+        hb_blob_t* pSubsetBlob = hb_face_reference_blob(pBuilderFace);
+        comphelper::ScopeGuard aBuilderBlobGuard([&]() { 
hb_blob_destroy(pSubsetBlob); });
 
-    hb_blob_t* pCFFBlob = hb_face_reference_table(pSubsetFace, HB_TAG('C', 
'F', 'F', ' '));
-    comphelper::ScopeGuard aCFFBlobGuard([&]() { hb_blob_destroy(pCFFBlob); });
-    if (pCFFBlob != hb_blob_get_empty())
+        unsigned int nSubsetLength;
+        const char* pSubsetData = hb_blob_get_data(pSubsetBlob, 
&nSubsetLength);
+        if (!pSubsetData || !nSubsetLength)
+            return false;
+
+        rOutBuffer.assign(reinterpret_cast<const sal_uInt8*>(pSubsetData),
+                          reinterpret_cast<const sal_uInt8*>(pSubsetData) + 
nSubsetLength);
+    }
+    else
     {
         // Ideally we should be outputting a CFF (Type1C) font here, but I 
couldn’t get it to work.
         // So we oconvert it to Type1 font instead.
@@ -611,24 +620,16 @@ bool 
PhysicalFontFace::CreateFontSubset(std::vector<sal_uInt8>& rOutBuffer,
         rInfo.m_nFontType = FontType::TYPE1_PFB;
 
         unsigned int nCffLen;
-        const unsigned char* pCffData
-            = reinterpret_cast<const unsigned 
char*>(hb_blob_get_data(pCFFBlob, &nCffLen));
-
-        if (!ConvertCFFfontToType1(pCffData, nCffLen, rOutBuffer, rInfo))
+        const char* pCffData = hb_blob_get_data(pCFFBlob, &nCffLen);
+        if (!pCffData || !nCffLen)
             return false;
-    }
-    else
-    {
-        rInfo.m_nFontType = FontType::SFNT_TTF;
 
-        unsigned int nSubsetLength;
-        const char* pSubsetData = nullptr;
-        pSubsetData = hb_blob_get_data(pSubsetBlob, &nSubsetLength);
-        if (!pSubsetData || !nSubsetLength)
+        if (!ConvertCFFfontToType1(reinterpret_cast<const unsigned 
char*>(pCffData), nCffLen,
+                                   rOutBuffer, rInfo))
+        {
+            SAL_WARN("vcl.fonts.cff", "Failed to convert CFF data to Type 1 
font");
             return false;
-
-        rOutBuffer.assign(reinterpret_cast<const sal_uInt8*>(pSubsetData),
-                          reinterpret_cast<const sal_uInt8*>(pSubsetData) + 
nSubsetLength);
+        }
     }
 
     return true;
commit 0a17b69e0784bcff70e759db4db26f486222e11f
Author:     Khaled Hosny <[email protected]>
AuthorDate: Sun Mar 8 23:16:38 2026 +0200
Commit:     Khaled Hosny <[email protected]>
CommitDate: Mon Mar 9 11:21:15 2026 +0100

    Assert less in CFF to Type 1 code
    
    The top-level function already returns a boolean, make many of the
    internal functions return false in case of failure and propagate that
    instead of asserting in debug builds and continuing with bad input in
    release builds.
    
    Change-Id: I00c5f9552eb114af1f406f5f1c2ead50fe6b97e4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201228
    Tested-by: Jenkins
    Reviewed-by: Khaled Hosny <[email protected]>

diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index 36e7d8a71c7a..c63d7650e5fe 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -501,6 +501,7 @@ certain functionality.
 @li @c vcl.filter.webp
 @li @c vcl.fonts - font-specific code
 @li @c vcl.fonts.detail
+@li @c vcl.fonts.cff - CFF font subsetting-specific code
 @li @c vcl.gdi - the GDI part of VCL, devices, bitmaps, etc.
 @li @c vcl.gdi.wndproc - Windows Procedure part of VCL
 @li @c vcl.gdi.fontmetric
diff --git a/vcl/source/fontsubset/cff.cxx b/vcl/source/fontsubset/cff.cxx
index c178a003c799..9ce598af4804 100644
--- a/vcl/source/fontsubset/cff.cxx
+++ b/vcl/source/fontsubset/cff.cxx
@@ -727,15 +727,15 @@ public:
     explicit CffContext( const U8* pBasePtr, int nBaseLen);
 
     bool    initialCffRead();
-    void    emitAsType1(class Type1Emitter&, FontSubsetInfo&);
+    bool    emitAsType1(class Type1Emitter&, FontSubsetInfo&);
 
 private:
-    void    convertCharStrings(std::vector<CharString>& rCharStrings,
+    bool    convertCharStrings(std::vector<CharString>& rCharStrings,
                                 int nGlyphCount, const sal_GlyphId* pGlyphIds 
= nullptr);
     int     convert2Type1Ops( CffLocal*, const U8* pType2Ops, int nType2Len, 
U8* pType1Ops);
-    void    convertOneTypeOp();
-    void    convertOneTypeEsc();
-    void    callType2Subr( bool bGlobal, int nSubrNumber);
+    bool    convertOneTypeOp();
+    bool    convertOneTypeEsc();
+    bool    callType2Subr( bool bGlobal, int nSubrNumber);
     sal_Int32 getReadOfs() const { return static_cast<sal_Int32>(mpReadPtr - 
mpBasePtr);}
 
     const U8* mpBasePtr;
@@ -902,7 +902,7 @@ void CffContext::readDictOp()
         //TODO: if( nStackIdx > 0)
         int nInt = 0;
         switch( *pCmdName) {
-        default: SAL_WARN("vcl.fonts", "unsupported DictOp.type='" << 
*pCmdName << "'."); break;
+        default: SAL_WARN("vcl.fonts.cff", "unsupported DictOp.type='" << 
*pCmdName << "'."); break;
         case 'b':   // bool
             nInt = popInt();
             switch( nOpId) {
@@ -1152,7 +1152,7 @@ void CffContext::writeCurveTo( int nStackPos,
     writeTypeOp( TYPE1OP::RCURVETO );
 }
 
-void CffContext::convertOneTypeOp()
+bool CffContext::convertOneTypeOp()
 {
     const int nType2Op = *(mpReadPtr++);
 
@@ -1160,7 +1160,8 @@ void CffContext::convertOneTypeOp()
     // convert each T2op
     switch( nType2Op) {
     case TYPE2OP::T2ESC:
-        convertOneTypeEsc();
+        if (!convertOneTypeEsc())
+            return false;
         break;
     case TYPE2OP::HSTEM:
     case TYPE2OP::VSTEM:
@@ -1242,12 +1243,13 @@ void CffContext::convertOneTypeOp()
         {
         nInt = popInt();
         const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR);
-        callType2Subr( bGlobal, nInt);
+        if (!callType2Subr( bGlobal, nInt))
+            return false;
         }
         break;
     case TYPE2OP::RETURN:
         // TODO: check that we are in a subroutine
-        return;
+        return true;
     case TYPE2OP::VMOVETO:
     case TYPE2OP::HMOVETO:
         if( mbNeedClose)
@@ -1382,91 +1384,107 @@ void CffContext::convertOneTypeOp()
             read2push();
         } else {
             popAll2Write( nType2Op);
-            assert(false && "TODO?");
+            SAL_WARN("vcl.fonts.cff", "unhandled type2op " << nType2Op);
+            return false;
         }
         break;
     }
+    return true;
 }
 
-void CffContext::convertOneTypeEsc()
+bool CffContext::convertOneTypeEsc()
 {
     const int nType2Esc = *(mpReadPtr++);
     ValType* pTop = &mnValStack[ mnStackIdx-1];
     // convert each T2op
     switch( nType2Esc) {
     case TYPE2OP::AND:
-        assert( mnStackIdx >= 2 );
+        if ( mnStackIdx < 2 )
+            return false;
         pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) & 
static_cast<int>(pTop[-1]));
         --mnStackIdx;
         break;
     case TYPE2OP::OR:
-        assert( mnStackIdx >= 2 );
+        if ( mnStackIdx < 2 )
+            return false;
         pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) | 
static_cast<int>(pTop[-1]));
         --mnStackIdx;
         break;
     case TYPE2OP::NOT:
-        assert( mnStackIdx >= 1 );
+        if ( mnStackIdx < 1 )
+            return false;
         pTop[0] = ValType(pTop[0] == 0);
         break;
     case TYPE2OP::ABS:
-        assert( mnStackIdx >= 1 );
+        if ( mnStackIdx < 1 )
+            return false;
         if( pTop[0] >= 0)
             break;
         [[fallthrough]];
     case TYPE2OP::NEG:
-        assert( mnStackIdx >= 1 );
+        if ( mnStackIdx < 1 )
+            return false;
         pTop[0] = -pTop[0];
         break;
     case TYPE2OP::ADD:
-        assert( mnStackIdx >= 2 );
+        if ( mnStackIdx < 2 )
+            return false;
         pTop[0] += pTop[-1];
         --mnStackIdx;
         break;
     case TYPE2OP::SUB:
-        assert( mnStackIdx >= 2 );
+        if ( mnStackIdx < 2 )
+            return false;
         pTop[0] -= pTop[-1];
         --mnStackIdx;
         break;
     case TYPE2OP::MUL:
-        assert( mnStackIdx >= 2 );
+        if ( mnStackIdx < 2 )
+            return false;
         if( pTop[-1])
             pTop[0] *= pTop[-1];
         --mnStackIdx;
         break;
     case TYPE2OP::DIV:
-        assert( mnStackIdx >= 2 );
+        if ( mnStackIdx < 2 )
+            return false;
         if( pTop[-1])
             pTop[0] /= pTop[-1];
         --mnStackIdx;
         break;
     case TYPE2OP::EQ:
-        assert( mnStackIdx >= 2 );
+        if ( mnStackIdx < 2 )
+            return false;
         pTop[0] = ValType(pTop[0] == pTop[-1]);
         --mnStackIdx;
         break;
     case TYPE2OP::DROP:
-        assert( mnStackIdx >= 1 );
+        if ( mnStackIdx < 1 )
+            return false;
         --mnStackIdx;
         break;
     case TYPE2OP::PUT: {
-        assert( mnStackIdx >= 2 );
+        if ( mnStackIdx < 2 )
+            return false;
         const int nIdx = static_cast<int>(pTop[0]);
-        assert( nIdx >= 0 );
-        assert( nIdx < NMAXTRANS );
+        if ( nIdx < 0 || nIdx >= NMAXTRANS )
+            return false;
         mnTransVals[ nIdx] = pTop[-1];
         mnStackIdx -= 2;
         break;
         }
     case TYPE2OP::GET: {
-        assert( mnStackIdx >= 1 );
+        if ( mnStackIdx < 1 )
+            return false;
         const int nIdx = static_cast<int>(pTop[0]);
-        assert( nIdx >= 0 );
-        assert( nIdx < NMAXTRANS );
+        if ( nIdx < 0 || nIdx >= NMAXTRANS )
+            return false;
         pTop[0] = mnTransVals[ nIdx ];
         break;
         }
     case TYPE2OP::IFELSE: {
-        assert( mnStackIdx >= 4 );
+        if ( mnStackIdx < 4 )
+            return false;
         if( pTop[-1] > pTop[0] )
             pTop[-3] = pTop[-2];
         mnStackIdx -= 3;
@@ -1480,37 +1498,42 @@ void CffContext::convertOneTypeEsc()
         // TODO: implement
         break;
     case TYPE2OP::DUP:
-        assert( mnStackIdx >= 1 );
+        if ( mnStackIdx < 1 )
+            return false;
         pTop[+1] = pTop[0];
         ++mnStackIdx;
         break;
     case TYPE2OP::EXCH: {
-        assert( mnStackIdx >= 2 );
+        if ( mnStackIdx < 2 )
+            return false;
         const ValType nVal = pTop[0];
         pTop[0] = pTop[-1];
         pTop[-1] = nVal;
         break;
         }
     case TYPE2OP::INDEX: {
-        assert( mnStackIdx >= 1 );
+        if ( mnStackIdx < 1 )
+            return false;
         const int nVal = static_cast<int>(pTop[0]);
-        assert( nVal >= 0 );
-        assert( nVal < mnStackIdx-1 );
+        if ( nVal < 0 || nVal >= mnStackIdx-1 )
+            return false;
         pTop[0] = pTop[-1-nVal];
         break;
         }
     case TYPE2OP::ROLL: {
-        assert( mnStackIdx >= 1 );
+        if ( mnStackIdx < 1 )
+            return false;
         const int nNum = static_cast<int>(pTop[0]);
-        assert( nNum >= 0);
-        assert( nNum < mnStackIdx-2 );
-        (void)nNum; // TODO: implement
+        if ( nNum < 0 || nNum >= mnStackIdx-2 )
+            return false;
+        // (void)nNum; // TODO: implement
         // TODO: implement: const int nOfs = static_cast<int>(pTop[-1]);
         mnStackIdx -= 2;
         break;
         }
     case TYPE2OP::HFLEX1: {
-            assert( mnStackIdx == 9);
+            if ( mnStackIdx != 9 )
+                return false;
 
             writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5,  0);
             writeCurveTo( mnStackIdx, -4,  0, -3, -2, -1,  0);
@@ -1520,7 +1543,8 @@ void CffContext::convertOneTypeEsc()
         }
         break;
     case TYPE2OP::HFLEX: {
-            assert( mnStackIdx == 7);
+            if ( mnStackIdx != 7 )
+                return false;
             ValType* pX = &mnValStack[ mnStackIdx];
 
             pX[+1] = -pX[-5]; // temp: +dy5==-dy2
@@ -1532,7 +1556,8 @@ void CffContext::convertOneTypeEsc()
         }
         break;
     case TYPE2OP::FLEX: {
-            assert( mnStackIdx == 13 );
+            if ( mnStackIdx != 13 )
+                return false;
             writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8 );
             writeCurveTo( mnStackIdx,  -7,  -6,  -5,  -4, -3, -2 );
             // ignoring ValType nFlexDepth = mnValStack[ mnStackIdx-1 ];
@@ -1540,7 +1565,8 @@ void CffContext::convertOneTypeEsc()
         }
         break;
     case TYPE2OP::FLEX1: {
-            assert( mnStackIdx == 11 );
+            if ( mnStackIdx != 11 )
+                return false;
             // write the first part of the flex1-hinted curve
             writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6 );
 
@@ -1561,30 +1587,36 @@ void CffContext::convertOneTypeEsc()
         }
         break;
     default:
-        SAL_WARN("vcl.fonts", "unhandled type2esc " << nType2Esc);
-        assert( false);
-        break;
+        SAL_WARN("vcl.fonts.cff", "unhandled type2esc " << nType2Esc);
+        return false;
     }
+    return true;
 }
 
-void CffContext::callType2Subr( bool bGlobal, int nSubrNumber)
+bool CffContext::callType2Subr( bool bGlobal, int nSubrNumber)
 {
     const U8* const pOldReadPtr = mpReadPtr;
     const U8* const pOldReadEnd = mpReadEnd;
 
     if( bGlobal ) {
         nSubrNumber += mnGlobalSubrBias;
-        seekIndexData( mnGlobalSubrBase, nSubrNumber);
+        if (seekIndexData( mnGlobalSubrBase, nSubrNumber) < 0)
+            return false;
     } else {
         nSubrNumber += mpCffLocal->mnLocalSubrBias;
-        seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber);
+        if (seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber) < 0)
+            return false;
     }
 
     while( mpReadPtr < mpReadEnd)
-        convertOneTypeOp();
+    {
+        if (!convertOneTypeOp())
+            return false;
+    }
 
     mpReadPtr = pOldReadPtr;
     mpReadEnd = pOldReadEnd;
+    return true;
 }
 
 int CffContext::convert2Type1Ops( CffLocal* pCffLocal, const U8* const pT2Ops, 
int nT2Len, U8* const pT1Ops)
@@ -1624,7 +1656,10 @@ int CffContext::convert2Type1Ops( CffLocal* pCffLocal, 
const U8* const pT2Ops, i
     mnHintSize=mnHorzHintSize=mnStackIdx=0; maCharWidth=-1;//#######
     mnCntrMask = 0;
     while( mpReadPtr < mpReadEnd)
-        convertOneTypeOp();
+    {
+        if (!convertOneTypeOp())
+            return -1;
+    }
     if( maCharWidth != -1 )
     {
         // overwrite earlier charWidth value, which we only now have
@@ -1723,7 +1758,8 @@ RealType CffContext::readRealVal()
 // prepare to access an element inside a CFF/CID index table
 int CffContext::seekIndexData( int nIndexBase, int nDataIndex)
 {
-    assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
+    if ( nIndexBase <= 0 || mpBasePtr + nIndexBase + 3 > mpBaseEnd)
+        return -1;
     if( nDataIndex < 0)
         return -1;
     mpReadPtr = mpBasePtr + nIndexBase;
@@ -1734,7 +1770,7 @@ int CffContext::seekIndexData( int nIndexBase, int 
nDataIndex)
     mpReadPtr += 3 + (nDataOfsSz * nDataIndex);
     int nOfs1 = 0;
     switch( nDataOfsSz) {
-        default: SAL_WARN("vcl.fonts", "       INVALID nDataOfsSz=" << 
nDataOfsSz); return -1;
+        default: SAL_WARN("vcl.fonts.cff", "   INVALID nDataOfsSz=" << 
nDataOfsSz); return -1;
         case 1: nOfs1 = mpReadPtr[0]; break;
         case 2: nOfs1 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
         case 3: nOfs1 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; 
break;
@@ -1752,10 +1788,8 @@ int CffContext::seekIndexData( int nIndexBase, int 
nDataIndex)
 
     mpReadPtr = mpBasePtr + (nIndexBase + 2) + nDataOfsSz * (nDataCount + 1) + 
nOfs1;
     mpReadEnd = mpReadPtr + (nOfs2 - nOfs1);
-    assert( nOfs1 >= 0);
-    assert( nOfs2 >= nOfs1);
-    assert( mpReadPtr <= mpBaseEnd);
-    assert( mpReadEnd <= mpBaseEnd);
+    if (nOfs1 < 0 || nOfs2 < nOfs1 || mpReadPtr > mpBaseEnd || mpReadEnd > 
mpBaseEnd)
+        return -1;
     return (nOfs2 - nOfs1);
 }
 
@@ -1770,7 +1804,7 @@ void CffContext::seekIndexEnd( int nIndexBase)
     assert( mpReadPtr <= mpBaseEnd);
     int nEndOfs = 0;
     switch( nDataOfsSz) {
-        default: SAL_WARN("vcl.fonts", "       INVALID nDataOfsSz=" << 
nDataOfsSz); return;
+        default: SAL_WARN("vcl.fonts.cff", "   INVALID nDataOfsSz=" << 
nDataOfsSz); return;
         case 1: nEndOfs = mpReadPtr[0]; break;
         case 2: nEndOfs = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
         case 3: nEndOfs = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + 
mpReadPtr[2];break;
@@ -1827,9 +1861,13 @@ bool CffContext::initialCffRead()
     const U8 nVerMinor = *(mpReadPtr++);
     const U8 nHeaderSize = *(mpReadPtr++);
     const U8 nOffsetSize = *(mpReadPtr++);
-    // TODO: is the version number useful for anything else?
-    assert( (nVerMajor == 1) && (nVerMinor == 0));
-    (void)(nVerMajor + nVerMinor + nOffsetSize); // avoid compiler warnings
+    if (nVerMajor != 1 || nVerMinor != 0)
+    {
+        SAL_WARN("vcl.fonts.cff", "Unsupported CFF version: " << 
int(nVerMajor) << "." << int(nVerMinor));
+        return false;
+    }
+    if (!nOffsetSize)
+        return false;
 
     // prepare access to the NameIndex
     mnNameIdxBase = nHeaderSize;
@@ -1841,10 +1879,12 @@ bool CffContext::initialCffRead()
     const int nTopDictCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
     if( nTopDictCount) {
         for( int i = 0; i < nTopDictCount; ++i) {
-            seekIndexData( nTopDictBase, i);
+            if (seekIndexData( nTopDictBase, i) < 0)
+                return false;
             while( mpReadPtr < mpReadEnd)
                 readDictOp();
-            assert( mpReadPtr == mpReadEnd);
+            if (mpReadPtr != mpReadEnd)
+                return false;
         }
     }
 
@@ -1877,17 +1917,19 @@ bool CffContext::initialCffRead()
         mnFDAryCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
         if (o3tl::make_unsigned(mnFDAryCount) >= SAL_N_ELEMENTS(maCffLocal))
         {
-            SAL_INFO("vcl.fonts", "CffContext: too many CFF in font");
+            SAL_INFO("vcl.fonts.cff", "CffContext: too many CFF in font");
             return false;
         }
 
         // read FDArray details to get access to the PRIVDICTs
         for( int i = 0; i < mnFDAryCount; ++i) {
             mpCffLocal = &maCffLocal[i];
-            seekIndexData( mnFontDictBase, i);
+            if (seekIndexData( mnFontDictBase, i) < 0)
+                return false;
             while( mpReadPtr < mpReadEnd)
                 readDictOp();
-            assert( mpReadPtr == mpReadEnd);
+            if (mpReadPtr != mpReadEnd)
+                return false;
         }
     }
 
@@ -1951,8 +1993,9 @@ OString CffContext::getString( int nStringID)
 // access a CID's FDSelect table
 int CffContext::getFDSelect( int nGlyphIndex) const
 {
-    assert( nGlyphIndex >= 0);
-    assert( nGlyphIndex < mnCharStrCount);
+    if ( nGlyphIndex < 0 || nGlyphIndex >= mnCharStrCount)
+        return -1;
+
     if( !mbCIDFont)
         return 0;
 
@@ -1984,11 +2027,10 @@ int CffContext::getFDSelect( int nGlyphIndex) const
                 }
             } break;
         default:    // invalid FDselect format
-            SAL_WARN("vcl.fonts", "invalid CFF.FdselType=" << nFDSelFormat);
+            SAL_WARN("vcl.fonts.cff", "invalid CFF.FdselType=" << 
nFDSelFormat);
             break;
     }
 
-    assert( false);
     return -1;
 }
 
@@ -2029,7 +2071,7 @@ int CffContext::getGlyphSID( int nGlyphIndex) const
             }
             break;
         default:
-            SAL_WARN("vcl.fonts", "ILLEGAL CFF-Charset format " << 
nCSetFormat);
+            SAL_WARN("vcl.fonts.cff", "ILLEGAL CFF-Charset format " << 
nCSetFormat);
             return -2;
     }
 
@@ -2205,7 +2247,7 @@ void Type1Emitter::emitValVector( const char* pLineHead, 
const char* pLineTail,
     maBuffer.append( pLineTail);
 }
 
-void CffContext::convertCharStrings(std::vector<CharString>& rCharStrings,
+bool CffContext::convertCharStrings(std::vector<CharString>& rCharStrings,
      int nGlyphCount, const sal_GlyphId* pGlyphIds)
 {
     // If we are doing extra glyphs used for seac operator, check for already
@@ -2215,7 +2257,8 @@ void 
CffContext::convertCharStrings(std::vector<CharString>& rCharStrings,
     for (int i = 0; i < nGlyphCount; ++i)
     {
         const int nCffGlyphId = pGlyphIds ? pGlyphIds[i] : i;
-        assert((nCffGlyphId >= 0) && (nCffGlyphId < mnCharStrCount));
+        if ((nCffGlyphId < 0) || (nCffGlyphId >= mnCharStrCount))
+            return false;
 
         if (!bCheckDuplicates)
         {
@@ -2229,23 +2272,27 @@ void 
CffContext::convertCharStrings(std::vector<CharString>& rCharStrings,
         // get privdict context matching to the glyph
         const int nFDSelect = getFDSelect(nCffGlyphId);
         if (nFDSelect < 0)
-            continue;
+            return false;
         mpCffLocal = &maCffLocal[nFDSelect];
 
         // convert the Type2op charstring to its Type1op counterpart
         const int nT2Len = seekIndexData(mnCharStrBase, nCffGlyphId);
-        assert(nT2Len > 0);
+        if (nT2Len <= 0)
+            return false;
 
         CharString aCharString;
         const int nT1Len = convert2Type1Ops(mpCffLocal, mpReadPtr, nT2Len, 
aCharString.aOps);
+        if (nT1Len < 0)
+            return false;
         aCharString.nLen = nT1Len;
         aCharString.nCffGlyphId = nCffGlyphId;
 
         rCharStrings.push_back(aCharString);
     }
+    return true;
 }
 
-void CffContext::emitAsType1(Type1Emitter& rEmitter, FontSubsetInfo& rFSInfo)
+bool CffContext::emitAsType1(Type1Emitter& rEmitter, FontSubsetInfo& rFSInfo)
 {
     OString aFontName = rFSInfo.m_aPSName.toUtf8();
     if (aFontName.getLength() > 255)
@@ -2437,14 +2484,16 @@ void CffContext::emitAsType1(Type1Emitter& rEmitter, 
FontSubsetInfo& rFSInfo)
     // emit the CharStrings for the requested glyphs
     std::vector<CharString> aCharStrings;
     mbDoSeac = true;
-    convertCharStrings(aCharStrings, mnCharStrCount);
+    if (!convertCharStrings(aCharStrings, mnCharStrCount))
+        return false;
 
     // The previous convertCharStrings might collect extra glyphs used in seac
     // operator, convert them as well
     if (!maExtraGlyphIds.empty())
     {
         mbDoSeac = false;
-        convertCharStrings(aCharStrings, maExtraGlyphIds.size(), 
maExtraGlyphIds.data());
+        if (!convertCharStrings(aCharStrings, maExtraGlyphIds.size(), 
maExtraGlyphIds.data()))
+            return false;
     }
     rEmitter.maBuffer.append(
         "2 index /CharStrings " + OString::number(aCharStrings.size()) + " 
dict dup begin
");
@@ -2486,6 +2535,8 @@ void CffContext::emitAsType1(Type1Emitter& rEmitter, 
FontSubsetInfo& rFSInfo)
     rEmitter.emitRawData( aPfxFooter, sizeof(aPfxFooter)-1);
 
     rFSInfo.m_nFontType = FontType::TYPE1_PFB;
+
+    return true;
 }
 
 namespace vcl
@@ -2495,15 +2546,15 @@ bool ConvertCFFfontToType1(const unsigned char* 
pFontBytes, int nByteLength,
                          FontSubsetInfo& rInfo)
 {
     CffContext aCff(pFontBytes, nByteLength);
-    bool bRC = aCff.initialCffRead();
-    if (!bRC)
-        return bRC;
+    if (!aCff.initialCffRead())
+        return false;
 
     SvMemoryStream aStream;
 
     // emit Type1 font from the CFF input
     Type1Emitter aType1Emitter(aStream);
-    aCff.emitAsType1(aType1Emitter, rInfo);
+    if (!aCff.emitAsType1(aType1Emitter, rInfo))
+        return false;
 
     rOutBuffer.assign(static_cast<const sal_uInt8*>(aStream.GetData()),
                       static_cast<const sal_uInt8*>(aStream.GetData()) + 
aStream.Tell());

Reply via email to