VirtualBox

Changeset 96550 in vbox for trunk/include/iprt


Ignore:
Timestamp:
Aug 30, 2022 1:04:57 AM (2 years ago)
Author:
vboxsync
Message:

iprt/bldprog-strtab*.cpp.h: Increased the size dictionary to make use of character codes needed for string encoding as well as slot 0xff in ASCII mode (otherwise used for UTF-8 sequence escaping), however slot zero is not yet usable. Improved the compression a bit further by consindering one separator character following a word, thus using 'VERR_' instead of 'VERR'. The the iprt defines-only header claims a 53% compression rate, up from 38%. bugref:9726

Location:
trunk/include/iprt
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/bldprog-strtab-template.cpp.h

    r96407 r96550  
    8585
    8686#ifdef BLDPROG_STRTAB_WITH_COMPRESSION
    87 # include <algorithm>
     87# include <iprt/asm.h>
    8888# include <map>
    8989# include <iprt/sanitized/string>
    90 # include <vector>
    91 
    92 typedef std::map<std::string, size_t> BLDPROGWORDFREQMAP;
    93 typedef BLDPROGWORDFREQMAP::value_type BLDPROGWORDFREQPAIR;
     90
     91# define BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE
     92typedef struct BLDPROGWORDFREQSTATS
     93{
     94    uint32_t cWithoutSep;   /**< Number of occurances without a separator. */
     95# ifdef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE
     96    uint32_t cWithSep;      /**< Number of occurance with a separator. */
     97    char     chSep;         /**< The separator.  First come basis. */
     98# endif
     99} BLDPROGWORDFREQSTATS;
     100
     101typedef std::map<std::string, BLDPROGWORDFREQSTATS> BLDPROGWORDFREQMAP;
    94102
    95103#endif
     
    148156
    149157#ifdef BLDPROG_STRTAB_WITH_COMPRESSION
    150     /** The 127 words we've picked to be indexed by reference. */
    151     BLDPROGSTRING       aCompDict[127];
    152     /** The frequency of the 127 dictionary entries.  */
    153     size_t              auCompDictFreq[127];
     158    /** The 256 words we've picked to be indexed by reference. */
     159    BLDPROGSTRING       aCompDict[256];
     160    /** The frequency of the 256 dictionary entries.  */
     161    size_t              auCompDictFreq[256];
    154162    /** Incoming strings pending compression. */
    155163    PBLDPROGSTRING     *papPendingStrings;
     
    161169     * @todo rewrite in plain C.  */
    162170    BLDPROGWORDFREQMAP  Frequencies;
     171    /** Map of characters used by input strings. */
     172    uint64_t            bmUsedChars[256/64];
    163173#endif
    164174
     
    200210    pThis->cPendingStrings = 0;
    201211    pThis->cMaxPendingStrings = cMaxStrings;
     212    memset(pThis->bmUsedChars, 0, sizeof(pThis->bmUsedChars));
     213    ASMBitSet(pThis->bmUsedChars, 0);    /* Some parts of the code still thinks zero is a terminator, so don't use it for now. */
     214# ifndef BLDPROG_STRTAB_PURE_ASCII
     215    ASMBitSet(pThis->bmUsedChars, 0xff); /* Reserve escape byte for codepoints above 127. */
     216# endif
    202217#endif
    203218
     
    300315static void bldProgStrTab_compressorAnalyzeString(PBLDPROGSTRTAB pThis, PBLDPROGSTRING pStr)
    301316{
     317    /*
     318     * Mark all the string characters as used.
     319     */
    302320    const char *psz = pStr->pszString;
     321    char ch;
     322    while ((ch = *psz++) != '\0')
     323        ASMBitSet(pThis->bmUsedChars, (uint8_t)ch);
    303324
    304325    /*
    305326     * For now we just consider words.
    306327     */
    307     char ch;
     328    psz = pStr->pszString;
    308329    while ((ch = *psz) != '\0')
    309330    {
     
    314335            BLDPROGWORDFREQMAP::iterator it = pThis->Frequencies.find(strWord);
    315336            if (it != pThis->Frequencies.end())
    316                 it->second += cchWord - 1;
     337            {
     338# ifdef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE
     339                char const chSep = psz[cchWord];
     340                if (chSep != '\0' && (it->second.chSep == chSep || it->second.chSep == '\0'))
     341                {
     342                    it->second.chSep = chSep;
     343                    it->second.cWithSep++;
     344                }
     345                else
     346# endif
     347                    it->second.cWithoutSep++;
     348            }
    317349            else
    318                 pThis->Frequencies[strWord] = 0;
    319 
    320             /** @todo could gain hits by including the space after the word, but that
    321              *        has the same accounting problems as the two words scenario below. */
     350            {
     351# ifdef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE
     352                char const chSep = psz[cchWord];
     353                if (chSep != '\0')
     354                {
     355                    BLDPROGWORDFREQSTATS NewWord = { 0, 0, chSep };
     356                    pThis->Frequencies[strWord] = NewWord;
     357                }
     358                else
     359# endif
     360                {
     361                    static BLDPROGWORDFREQSTATS s_NewWord = { 0 };
     362                    pThis->Frequencies[strWord] = s_NewWord;
     363                }
     364            }
    322365
    323366# if 0 /** @todo need better accounting for overlapping alternatives before this can be enabled. */
     
    525568
    526569        /* Check for g_aWord matches. */
    527         size_t cchMax = pszSrcEnd - pszSrc;
    528         for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++)
    529         {
    530             size_t cchLen = pThis->aCompDict[i].cchString;
    531             if (   cchLen >= cchWord
    532                 && cchLen <= cchMax
    533                 && memcmp(pThis->aCompDict[i].pszString, pszSrc, cchLen) == 0)
    534             {
    535                 *pszDst++ = (unsigned char)(0x80 | i);
    536                 pszSrc += cchLen;
    537                 cchWord = 0;
    538                 break;
    539             }
    540         }
    541 
    542         if (cchWord)
     570        if (cchWord > 1)
     571        {
     572            size_t cchMax = pszSrcEnd - pszSrc;
     573            for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++)
     574            {
     575                size_t cchLen = pThis->aCompDict[i].cchString;
     576                if (   cchLen >= cchWord
     577                    && cchLen <= cchMax
     578                    && memcmp(pThis->aCompDict[i].pszString, pszSrc, cchLen) == 0)
     579                {
     580                    *pszDst++ = (unsigned char)i;
     581                    pszSrc += cchLen;
     582                    cchWord = 0;
     583                    break;
     584                }
     585            }
     586        }
     587
     588        if (cchWord > 0)
    543589        {
    544590            /* Copy the current word. */
     
    574620
    575621/**
    576  * For sorting the frequency fidning in descending order.
    577  *
    578  * Comparison operators are put outside to make older gcc versions (like 4.1.1
    579  * on lnx64-rel) happy.
    580  */
    581 class WordFreqSortEntry
     622 * Entry in SortedDictionary.
     623 *
     624 * Uses variable length string member, so not class and allocated via malloc.
     625 */
     626struct SortedDictionaryEntry
     627{
     628    size_t      m_cchGain;
     629    size_t      m_cchString;
     630    char        m_szString[RT_FLEXIBLE_ARRAY];
     631
     632    /** Allocates and initializes a new entry. */
     633    static SortedDictionaryEntry *allocate(const char *a_pch, size_t a_cch, size_t a_cchGain, char a_chSep)
     634    {
     635        size_t cbString = a_cch + !!a_chSep + 1;
     636        SortedDictionaryEntry *pNew = (SortedDictionaryEntry *)malloc(RT_UOFFSETOF(SortedDictionaryEntry, m_szString) + cbString);
     637        if (pNew)
     638        {
     639            pNew->m_cchGain   = a_cchGain;
     640            memcpy(pNew->m_szString, a_pch, a_cch);
     641            if (a_chSep)
     642                pNew->m_szString[a_cch++] = a_chSep;
     643            pNew->m_szString[a_cch] = '\0';
     644            pNew->m_cchString = a_cch;
     645        }
     646        return pNew;
     647    }
     648
     649
     650    /** Compares this dictionary entry with an incoming one.
     651     * @retval -1 if this entry is of less worth than the new one.
     652     * @retval  0 if this entry is of equal worth to the new one.
     653     * @retval +1 if this entry is of more worth than the new one.
     654     */
     655    int compare(size_t a_cchGain, size_t a_cchString)
     656    {
     657        /* Higher gain is preferred of course: */
     658        if (m_cchGain < a_cchGain)
     659            return -1;
     660        if (m_cchGain > a_cchGain)
     661            return 1;
     662
     663        /* Gain is the same. Prefer the shorter string, as it will result in a shorter string table: */
     664        if (m_cchString > a_cchString)
     665            return -1;
     666        if (m_cchString < a_cchString)
     667            return 1;
     668        return 0;
     669    }
     670};
     671
     672
     673/**
     674 * Insertion sort dictionary that keeps the 256 best words.
     675 *
     676 * Used by bldProgStrTab_compressorDoStringCompression to pick the dictionary
     677 * words.
     678 */
     679class SortedDictionary
    582680{
    583681public:
    584     BLDPROGWORDFREQPAIR const *m_pPair;
    585 
    586 public:
    587     WordFreqSortEntry(BLDPROGWORDFREQPAIR const *pPair) : m_pPair(pPair) {}
     682    size_t                  m_cEntries;
     683    SortedDictionaryEntry  *m_apEntries[256];
     684
     685    SortedDictionary()
     686        : m_cEntries(0)
     687    {
     688        for (size_t i = 0; i < RT_ELEMENTS(m_apEntries); i++)
     689            m_apEntries[i] = NULL;
     690    }
     691
     692    ~SortedDictionary()
     693    {
     694        while (m_cEntries > 0)
     695        {
     696            free(m_apEntries[--m_cEntries]);
     697            m_apEntries[m_cEntries] = NULL;
     698        }
     699    }
     700
     701
     702    /**
     703     * Inserts a new entry, if it's worth it.
     704     * @returns true on succes, false if out of memory.
     705     */
     706    bool insert(const char *a_pchString, size_t a_cchStringBase, size_t a_cchGain, char a_chSep = 0)
     707    {
     708        size_t const cchString = a_cchStringBase + (a_chSep + 1);
     709
     710        /*
     711         * Drop the insert if the symbol table is full and the insert is less worth the last entry:
     712         */
     713        if (   m_cEntries >= RT_ELEMENTS(m_apEntries)
     714            && m_apEntries[RT_ELEMENTS(m_apEntries) - 1]->compare(a_cchGain, cchString) >= 0)
     715            return true;
     716
     717        /*
     718         * Create a new entry to insert.
     719         */
     720        SortedDictionaryEntry *pNewEntry = SortedDictionaryEntry::allocate(a_pchString, a_cchStringBase, a_cchGain, a_chSep);
     721        if (!pNewEntry)
     722            return false;
     723
     724        /*
     725         * Find the insert point.
     726         */
     727        if (m_cEntries == 0)
     728        {
     729            m_apEntries[0] = pNewEntry;
     730            m_cEntries     = 1;
     731        }
     732        else
     733        {
     734            /* If table is full, drop the last entry before we start (already made
     735               sure the incoming entry is preferable to the one were dropping): */
     736            if (m_cEntries >= RT_ELEMENTS(m_apEntries))
     737            {
     738                free(m_apEntries[RT_ELEMENTS(m_apEntries) - 1]);
     739                m_apEntries[RT_ELEMENTS(m_apEntries) - 1] = NULL;
     740                m_cEntries = RT_ELEMENTS(m_apEntries) - 1;
     741            }
     742
     743            /* Find where to insert the new entry: */
     744            /** @todo use binary search. */
     745            size_t i = m_cEntries;
     746            while (i > 0 && m_apEntries[i - 1]->compare(a_cchGain, cchString) < 0)
     747                i--;
     748
     749            /* Shift entries to make room and insert the new entry. */
     750            if (i < m_cEntries)
     751                memmove(&m_apEntries[i + 1], &m_apEntries[i], (m_cEntries - i) * sizeof(m_apEntries[0]));
     752            m_apEntries[i] = pNewEntry;
     753            m_cEntries++;
     754        }
     755        return true;
     756    }
    588757};
    589 
    590 bool operator == (WordFreqSortEntry const &rLeft, WordFreqSortEntry const &rRight)
    591 {
    592     return rLeft.m_pPair->second == rRight.m_pPair->second;
    593 }
    594 
    595 bool operator <  (WordFreqSortEntry const &rLeft, WordFreqSortEntry const &rRight)
    596 {
    597     return rLeft.m_pPair->second >  rRight.m_pPair->second;
    598 }
    599758
    600759
     
    608767{
    609768    /*
    610      * Sort the frequency analyzis result and pick the top 127 ones.
    611      */
    612     std::vector<WordFreqSortEntry> SortMap;
     769     * Sort the frequency analyzis result and pick the top entries for any
     770     * available dictionary slots.
     771     */
     772    SortedDictionary SortedDict;
    613773    for (BLDPROGWORDFREQMAP::iterator it = pThis->Frequencies.begin(); it != pThis->Frequencies.end(); ++it)
    614774    {
    615         BLDPROGWORDFREQPAIR const &rPair = *it;
    616         SortMap.push_back(WordFreqSortEntry(&rPair));
    617     }
    618 
    619     sort(SortMap.begin(), SortMap.end());
    620 
    621     size_t cb = 0;
    622     size_t i  = 0;
    623     for (std::vector<WordFreqSortEntry>::iterator it = SortMap.begin();
    624          it != SortMap.end() && i < RT_ELEMENTS(pThis->aCompDict);
    625          ++it, i++)
    626     {
    627         pThis->auCompDictFreq[i]      = it->m_pPair->second;
    628         pThis->aCompDict[i].cchString = it->m_pPair->first.length();
     775        bool fInsert;
     776        size_t const cchString      = it->first.length();
     777# ifndef BLDPROG_STRTAB_WITH_WORD_SEP_ALTERNATIVE
     778        size_t const cchGainWithout = it->second.cWithoutSep * cchString;
     779# else
     780        size_t const cchGainWithout = (it->second.cWithoutSep + it->second.cWithSep) * cchString;
     781        size_t const cchGainWith    = it->second.cWithSep * (cchString + 1);
     782        if (cchGainWith > cchGainWithout)
     783            fInsert = SortedDict.insert(it->first.c_str(), cchString, cchGainWith, it->second.chSep);
     784        else
     785# endif
     786            fInsert = SortedDict.insert(it->first.c_str(), cchString, cchGainWithout);
     787        if (!fInsert)
     788            return false;
     789    }
     790
     791    size_t cb     = 0;
     792    size_t cWords = 0;
     793    size_t iDict  = 0;
     794    for (size_t i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++)
     795    {
     796        char        szTmp[2] = { (char)i, '\0' };
     797        const char *psz      = szTmp;
     798        if (   ASMBitTest(pThis->bmUsedChars, (int32_t)i)
     799            || iDict >= SortedDict.m_cEntries)
     800        {
     801            /* character entry  */
     802            pThis->auCompDictFreq[i]      = 0;
     803            pThis->aCompDict[i].cchString = 1;
     804        }
     805        else
     806        {
     807            /* word entry */
     808            cb += SortedDict.m_apEntries[iDict]->m_cchGain;
     809            pThis->auCompDictFreq[i]      = SortedDict.m_apEntries[iDict]->m_cchGain;
     810            pThis->aCompDict[i].cchString = SortedDict.m_apEntries[iDict]->m_cchString;
     811            psz = SortedDict.m_apEntries[iDict]->m_szString;
     812            cWords++;
     813            iDict++;
     814        }
    629815        pThis->aCompDict[i].pszString = (char *)malloc(pThis->aCompDict[i].cchString + 1);
    630816        if (pThis->aCompDict[i].pszString)
    631             memcpy(pThis->aCompDict[i].pszString, it->m_pPair->first.c_str(), pThis->aCompDict[i].cchString + 1);
     817            memcpy(pThis->aCompDict[i].pszString, psz, pThis->aCompDict[i].cchString + 1);
    632818        else
    633819            return false;
    634         cb += it->m_pPair->second;
    635820    }
    636821
    637822    if (fVerbose)
    638         printf("debug: Estimated string compression saving: %u bytes\n", (unsigned)cb);
     823        printf("debug: Estimated string compression saving: %u bytes\n"
     824               "debug: %u words, %u characters\n"
     825               , (unsigned)cb, (unsigned)cWords, (unsigned)(RT_ELEMENTS(pThis->aCompDict) - cWords));
    639826
    640827    /*
     
    647834    size_t cchNewMax = 0;
    648835    size_t cchNewMin = BLDPROG_STRTAB_MAX_STRLEN;
    649     i = pThis->cPendingStrings;
     836    size_t i        = pThis->cPendingStrings;
    650837    while (i-- > 0)
    651838    {
     
    760947     */
    761948    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++)
    762         bldProgStrTab_AddStringToHashTab(pThis, &pThis->aCompDict[i]);
     949        if (pThis->aCompDict[i].cchString > 1)
     950            bldProgStrTab_AddStringToHashTab(pThis, &pThis->aCompDict[i]);
     951# ifdef RT_STRICT
     952        else if (pThis->aCompDict[i].cchString != 1)
     953            abort();
     954# endif
    763955#endif
    764956    if (fVerbose)
     
    799991    for (size_t i = 0; i < pThis->cSortedStrings; i++)
    800992    {
    801         PBLDPROGSTRING       pCur    = pThis->papSortedStrings[i];
     993        PBLDPROGSTRING      pCur      = pThis->papSortedStrings[i];
    802994        const char * const  pszCur    = pCur->pszString;
    803995        size_t       const  cchCur    = pCur->cchString;
     
    9141106    while ((uch = *psz++) != '\0')
    9151107    {
     1108#ifdef BLDPROG_STRTAB_WITH_COMPRESSION
     1109        if (pThis->aCompDict[uch].cchString == 1)
     1110#else
    9161111        if (!(uch & 0x80))
     1112#endif
    9171113        {
    9181114            if (uch != '\'' && uch != '\\')
     
    9251121        }
    9261122#ifdef BLDPROG_STRTAB_WITH_COMPRESSION
    927         else if (uch != 0xff)
    928             fputs(pThis->aCompDict[uch & 0x7f].pszString, pOut);
    929         else
    930         {
    931 # ifdef BLDPROG_STRTAB_PURE_ASCII
    932             abort();
    933 # else
     1123# ifndef BLDPROG_STRTAB_PURE_ASCII
     1124        else if (uch == 0xff)
     1125        {
    9341126            RTUNICP uc = RTStrGetCp((const char *)psz);
    9351127            psz += RTStrCpSize(uc);
    9361128            fprintf(pOut, "\\u%04x", uc);
    937 # endif
    938         }
     1129        }
     1130# else
     1131        else
     1132            fputs(pThis->aCompDict[uch].pszString, pOut);
     1133# endif
    9391134#else
    9401135        else
     
    9681163# ifdef BLDPROG_STRTAB_WITH_COMPRESSION
    9691164    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++)
    970         BldProgStrTab_CheckStrTabString(pThis, &pThis->aCompDict[i]);
     1165    {
     1166        if (ASMBitTest(pThis->bmUsedChars, (int32_t)i)
     1167            ? pThis->aCompDict[i].cchString != 1 : pThis->aCompDict[i].cchString < 1)
     1168            abort();
     1169        if (pThis->aCompDict[i].cchString > 1)
     1170            BldProgStrTab_CheckStrTabString(pThis, &pThis->aCompDict[i]);
     1171    }
    9711172# endif
    9721173#endif
     
    9831184    for (unsigned i = 0x7f; i < 0x100; i++)
    9841185        abCharCat[i] = 2;
     1186#ifdef BLDPROG_STRTAB_WITH_COMPRESSION
     1187    for (unsigned i = 0; i < 0x100; i++)
     1188        if (!ASMBitTest(pThis->bmUsedChars, (int32_t)i)) /* Encode table references using '\xYY'. */
     1189            abCharCat[i] = 2;
     1190#endif
    9851191
    9861192    /*
     
    10011207        if (offEnd > off)
    10021208        {
    1003             /* Comment with a uncompressed and more readable version of the string. */
     1209            /* Comment with an uncompressed and more readable version of the string. */
    10041210            if (off == pCur->offStrTab)
    10051211                fprintf(pOut, "/* 0x%05x = \"", off);
     
    10461252            pszBaseName, (unsigned)RT_ELEMENTS(pThis->aCompDict));
    10471253    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aCompDict); i++)
    1048         fprintf(pOut, "    { %#08x, %#04x }, // %6lu - %s\n",
    1049                 pThis->aCompDict[i].offStrTab, (unsigned)pThis->aCompDict[i].cchString,
    1050                 (unsigned long)pThis->auCompDictFreq[i], pThis->aCompDict[i].pszString);
     1254        if (pThis->aCompDict[i].cchString > 1)
     1255            fprintf(pOut, "    /*[%3u]=*/ { %#08x, %#04x }, // %6lu - %s\n", i,
     1256                    pThis->aCompDict[i].offStrTab, (unsigned)pThis->aCompDict[i].cchString,
     1257                    (unsigned long)pThis->auCompDictFreq[i], pThis->aCompDict[i].pszString);
     1258# ifndef BLDPROG_STRTAB_PURE_ASCII
     1259        else if (i == 0xff)
     1260            fprintf(pOut, "    /*[%3u]=*/ { 0x000000, 0x00 }, // UTF-8 escape\n", i);
     1261# endif
     1262        else if (i == 0)
     1263            fprintf(pOut, "    /*[%3u]=*/ { 0x000000, 0x00 }, // unused, because zero terminator\n", i);
     1264        else if (i < 0x20)
     1265            fprintf(pOut, "    /*[%3u]=*/ { 0x000000, 0x00 }, // %02x\n", i, i);
     1266        else
     1267            fprintf(pOut, "    /*[%3u]=*/ { 0x000000, 0x00 }, // '%c'\n", i,  (char)i);
    10511268    fprintf(pOut, "};\n\n");
    10521269#endif
     
    10681285            "    /*.paCompDict = */ &g_aCompDict%s[0]\n"
    10691286            "};\n"
    1070             , (unsigned)RT_ELEMENTS(pThis->aCompDict), pszBaseName);
     1287# ifndef BLDPROG_STRTAB_PURE_ASCII /* 255 or 256 entries is how the decoder knows  */
     1288            , (unsigned)RT_ELEMENTS(pThis->aCompDict) - 1,
     1289# else
     1290            , (unsigned)RT_ELEMENTS(pThis->aCompDict),
     1291# endif
     1292            pszBaseName);
    10711293#else
    10721294    fprintf(pOut,
  • trunk/include/iprt/bldprog-strtab.h

    r96407 r96550  
    6464    const char         *pchStrTab;
    6565    uint32_t            cchStrTab;
    66     uint8_t             cCompDict;
     66    uint32_t            cCompDict;
    6767    PCRTBLDPROGSTRREF   paCompDict;
    6868} RTBLDPROGSTRTAB;
     
    101101    if (pStrTab->cCompDict)
    102102    {
     103        Assert(pStrTab->cCompDict == 256 || pStrTab->cCompDict == 255);
     104
    103105        /*
    104          * Could be compressed, decompress it.
     106         * Is compressed, decompress it.
    105107         */
    106108        char * const pchDstStart = pszDst;
     
    109111        {
    110112            unsigned char uch = *(unsigned char *)pchSrc++;
    111             if (!(uch & 0x80))
    112             {
    113                 /*
    114                  * Plain text.
    115                  */
    116                 AssertReturn(cbDst > 1, RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst));
    117                 cbDst    -= 1;
    118                 *pszDst++ = (char)uch;
    119                 Assert(uch != 0);
    120             }
    121             else if (uch != 0xff)
    122             {
    123                 /*
    124                  * Dictionary reference. (No UTF-8 unescaping necessary here.)
    125                  */
    126                 PCRTBLDPROGSTRREF   pWord   = &pStrTab->paCompDict[uch & 0x7f];
     113            if (uch != 0xff || pStrTab->cCompDict > 0xff)
     114            {
     115                /*
     116                 * Look it up in the dictionary, either a single 7-bit character or a word.
     117                 * Either way, no UTF-8 unescaping necessary.
     118                 */
     119                PCRTBLDPROGSTRREF   pWord   = &pStrTab->paCompDict[uch];
    127120                size_t const        cchWord = pWord->cch;
    128                 AssertReturn((size_t)pWord->off + cchWord <= pStrTab->cchStrTab,
    129                              RTBldProgStrTabQueryStringFail(VERR_INVALID_PARAMETER, pchDstStart, pszDst, cbDst));
    130                 AssertReturn(cbDst > cchWord,
    131                              RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst));
    132                 memcpy(pszDst, &pStrTab->pchStrTab[pWord->off], cchWord);
    133                 pszDst += cchWord;
    134                 cbDst  -= cchWord;
     121                if (cchWord <= 1)
     122                {
     123                    Assert(uch != 0);
     124                    Assert(uch <= 127);
     125                    AssertReturn(cbDst > 1, RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst));
     126                    cbDst    -= 1;
     127                    *pszDst++ = (char)uch;
     128                }
     129                else
     130                {
     131                    Assert(cchWord > 1);
     132                    AssertReturn((size_t)pWord->off + cchWord <= pStrTab->cchStrTab,
     133                                 RTBldProgStrTabQueryStringFail(VERR_INVALID_PARAMETER, pchDstStart, pszDst, cbDst));
     134                    AssertReturn(cbDst > cchWord,
     135                                 RTBldProgStrTabQueryStringFail(VERR_BUFFER_OVERFLOW, pchDstStart, pszDst, cbDst));
     136                    memcpy(pszDst, &pStrTab->pchStrTab[pWord->off], cchWord);
     137                    pszDst += cchWord;
     138                    cbDst  -= cchWord;
     139                }
    135140            }
    136141            else
     
    195200    if (pStrTab->cCompDict)
    196201    {
     202        Assert(pStrTab->cCompDict == 256 || pStrTab->cCompDict == 255);
     203
    197204        /*
    198205         * Could be compressed, decompress it.
     
    203210        {
    204211            unsigned char uch = *(unsigned char *)pchSrc++;
    205             if (!(uch & 0x80))
    206             {
    207                 /*
    208                  * Plain text.
    209                  */
    210                 Assert(uch != 0);
    211                 cchRet += pfnOutput(pvArgOutput, (const char *)&uch, 1);
    212             }
    213             else if (uch != 0xff)
    214             {
    215                 /*
    216                  * Dictionary reference. (No UTF-8 unescaping necessary here.)
    217                  */
    218                 PCRTBLDPROGSTRREF   pWord   = &pStrTab->paCompDict[uch & 0x7f];
     212            if (uch != 0xff || pStrTab->cCompDict > 0xff)
     213            {
     214                /*
     215                 * Look it up in the dictionary, either a single 7-bit character or a word.
     216                 * Either way, no UTF-8 unescaping necessary.
     217                 */
     218                PCRTBLDPROGSTRREF   pWord   = &pStrTab->paCompDict[uch];
    219219                size_t const        cchWord = pWord->cch;
    220                 AssertReturn((size_t)pWord->off + cchWord <= pStrTab->cchStrTab, cchRet);
    221 
    222                 cchRet += pfnOutput(pvArgOutput, &pStrTab->pchStrTab[pWord->off], cchWord);
     220                if (cchWord <= 1)
     221                {
     222                    Assert(uch != 0);
     223                    Assert(uch <= 127);
     224                    cchRet += pfnOutput(pvArgOutput, (const char *)&uch, 1);
     225                }
     226                else
     227                {
     228                    Assert(cchWord > 1);
     229                    AssertReturn((size_t)pWord->off + cchWord <= pStrTab->cchStrTab, cchRet);
     230
     231                    cchRet += pfnOutput(pvArgOutput, &pStrTab->pchStrTab[pWord->off], cchWord);
     232                }
    223233            }
    224234            else
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette