This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123GH6PM: GrStringGet bug when utilizing sub-string

Part Number: TM4C123GH6PM

    

This is a bug report for GrStringGet in revision 2.1.3.156 of the Tiva Graphics Library; I already found a solution.

I am using a CSV file with translated strings.  It gets converted to an uncompressed string table with "mkstringtable -u ...".  In one line of the file I had something equivalent to

     "1234567890abcd", "12345678", ...

The second string was getting encoded by mkstringtable by referring to the first string, of which it is the first eight characters.  When requesting the second string using GrStringGet(), I was getting the correct eight characters followed by two more characters that changed somewhat randomly (probably leftover stuff on the stack).  Also, when this happened, GrStringGet() returned zero rather than eight (the correct string length) or ten (the actual length reported by strlen() for the returned string).  

The problematic string was being handled by the second place in GrStringGet() with the comment "Copy this portion of the string to the output buffer."  Most of the other strings (which worked right) were handled by the following case, which is commented with "Now copy the last piece of the string."  The latter (working) case ends with this code:

// If we had not copied any characters before hitting this case,
// initialize the output pointer (this keeps the code at the end of
// the function that returns the length happy). This will be the
// case if we are using an uncompressed string table.
//
if(!pui8BufferOut)
{
    pui8BufferOut = (uint8_t *)pcData + (i32Idx + i32Buf);
}

I think adding that code to the problematic section would fix it, but I accomplished the same thing without adding code by rearranging how the "if" statements were nested to make both cases execute that code.  I don't see a way to attach a file;  if I can't find one I will follow up with at least a snippet of the code.

Steve

  • This is my modified version of GrStringGet():

    //*****************************************************************************
    //
    //! This function returns a string from the current string table.
    //!
    //! \param i32Index is the index of the string to retrieve.
    //! \param pcData is the pointer to the buffer to store the string into.
    //! \param ui32Size is the size of the buffer provided by pcData.
    //!
    //! This function will return a string from the string table in the language
    //! set by the GrStringLanguageSet() function.  The value passed in \e iIndex
    //! parameter is the string that is being requested and will be returned in
    //! the buffer provided in the \e pcData parameter.  The amount of data
    //! returned will be limited by the ui32Size parameter.
    //!
    //! \return Returns the number of valid bytes returned in the \e pcData buffer.
    //
    //*****************************************************************************
    uint32_t
    GrStringGet(int32_t i32Index, char *pcData, uint32_t ui32Size)
    {
        uint32_t ui32Len, ui32Offset, ui32SubCode[16];
        int32_t i32Pos, i32Idx, i32Bit, i32Skip, i32Buf;
        uint8_t *pui8BufferOut;
        const uint8_t *pui8String;
    
        ASSERT(i32Index < g_ui16NumStrings);
        ASSERT(pcData != 0);
    
        //
        // Initialize the output buffer state.
        //
        i32Pos = 0;
        pui8BufferOut = 0;
    
        //
        // if built up from another string, we need to process that
        // this could nest multiple layers, so we follow in
        //
        ui32SubCode[i32Pos] = g_pui32StringTable[(g_ui16Language *
                                                  g_ui16NumStrings) + i32Index];
    
        if(SC_GET_LEN(ui32SubCode[i32Pos]))
        {
            //
            // recurse down
            //
            while(i32Pos < 16)
            {
                //
                // Copy over the partial (if any) from a previous string.
                //
                i32Idx = SC_GET_INDEX(ui32SubCode[i32Pos++]);
    
                ui32SubCode[i32Pos] = g_pui32StringTable[(g_ui16Language *
                                                          g_ui16NumStrings) +
                                                         i32Idx];
    
                if(!SC_GET_LEN(ui32SubCode[i32Pos]))
                {
                    //
                    // not linked, just string
                    //
                    break;
                }
            }
        }
    
        //
        // Now work backwards out.
        //
        i32Idx = 0;
    
        //
        // Build up the string in pieces.
        //
        while(i32Pos >= 0)
        {
            //
            // Get the offset in string table.
            //
            ui32Offset = SC_GET_OFF(ui32SubCode[i32Pos]);
    
            if(ui32Offset == SC_IS_NULL)
            {
                //
                // An empty string.
                //
                pcData[i32Idx] = 0;
            }
            else if(ui32Offset & SC_FLAG_COMPRESSED)
            {
                //
                // This is a compressed string so initialize the pointer to the
                // compressed data.
                //
                pui8String = g_pui8StringData + (ui32Offset & SC_OFFSET_M);
    
                //
                // Initialize the bit variables.
                //
                i32Bit = 0;
                i32Skip = 0;
    
                //
                // Make a pointer to the current buffer out location.
                //
                pui8BufferOut = (uint8_t *)pcData + i32Idx;
    
                //
                // If the out buffer is beyond the maximum size then just break
                // out and return what we have so far.
                //
                if((char *)pui8BufferOut > (pcData + ui32Size))
                {
                    break;
                }
    
                //
                // Now build up real string by decompressing bits.
                //
                if(!SC_GET_LEN(ui32SubCode[i32Pos]) &&
                   SC_GET_INDEX(ui32SubCode[i32Pos]))
                {
                    i32Skip = SC_GET_INDEX(ui32SubCode[i32Pos]);
    
                    if(i32Pos)
                    {
                        ui32Len = SC_GET_LEN(ui32SubCode[i32Pos - 1]);
                    }
                    else
                    {
                        ui32Len = (i32Skip & 0x3f);
                    }
    
                    i32Skip >>= 6;
                    i32Idx += ui32Len;
                    ui32Len += i32Skip;
                }
                else if(i32Pos)
                {
                    //
                    // Get the length of the partial string.
                    //
                    ui32Len = SC_GET_LEN(ui32SubCode[i32Pos - 1]) - i32Idx;
                    i32Idx += ui32Len;
                }
                else if(!SC_GET_LEN(ui32SubCode[0]) &&
                        SC_GET_INDEX(ui32SubCode[0]))
                {
                    ui32Len = SC_GET_INDEX(ui32SubCode[0]);
                    i32Skip = ui32Len >> 6;
                    ui32Len = (ui32Len & 0x3f) + i32Skip;
                }
                else
                {
                    //
                    // Arbitrary as null character ends the string.
                    //
                    ui32Len = 1024;
                }
    
                for(; ui32Len; ui32Len--)
                {
                    //
                    // Packed 6 bits for each char
                    //
                    *pui8BufferOut = (*pui8String >> i32Bit) & 0x3f;
    
                    if(i32Bit >= 2)
                    {
                        *pui8BufferOut |= (*++pui8String << (8 - i32Bit)) & 0x3f;
                    }
    
                    i32Bit = (i32Bit + 6) & 0x7;
    
                    if(!*pui8BufferOut)
                    {
                        //
                        // end of string
                        //
                        break;
                    }
    
                    if(i32Skip)
                    {
                        i32Skip--;
                        continue;
                    }
    
                    //
                    // Put back removed bit
                    //
                    *pui8BufferOut |= 0x40;
    
                    //
                    // Now look for a few special chars we mapped up into other
                    // characters.
                    //
                    if(*pui8BufferOut == '`')
                    {
                        *pui8BufferOut = ' ';
                    }
                    else if(*pui8BufferOut == '~')
                    {
                        *pui8BufferOut = '-';
                    }
                    else if(*pui8BufferOut == 0x7f)
                    {
                        *pui8BufferOut = '.';
                    }
                    else if(*pui8BufferOut == '\\')
                    {
                        *pui8BufferOut = ':';
                    }
    
                    //
                    // Increment the pointer and break out if the pointer is now
                    // beyond the end of the buffer provided.
                    //
                    pui8BufferOut++;
    
                    if((char *)pui8BufferOut >= (pcData + ui32Size))
                    {
                        break;
                    }
                }
            }
            else if(i32Pos)
            {
                //
                // Part of another string
                //
                ui32Len = SC_GET_LEN(ui32SubCode[i32Pos - 1]) - i32Idx;
    
                //
                // Prevent this copy from going beyond the end of the buffer
                // provided.
                //
                if((i32Idx + ui32Len) > ui32Size)
                {
                    ui32Len = ui32Size - i32Idx;
                }
    
                //
                // Copy this portion of the string to the output buffer.
                //
                for(i32Buf = 0; i32Buf < ui32Len; i32Buf++)
                {
                    pcData[i32Idx + i32Buf] = g_pui8StringData[ui32Offset +
                                                               i32Buf];
                }
    
                i32Idx += ui32Len;
            }
            else
            {
    			if(SC_GET_INDEX(ui32SubCode[0]) && !SC_GET_LEN(ui32SubCode[0]))
    			{
    				//
    				// Copy this portion of the string to the output buffer.
    				//
    				for(i32Buf = 0; i32Buf < SC_GET_INDEX(ui32SubCode[0]); i32Buf++)
    				{
    					if((i32Idx + i32Buf) < ui32Size)
    					{
    						pcData[i32Idx + i32Buf] = g_pui8StringData[ui32Offset +
    																   i32Buf];
    					}
    					else
    					{
    						break;
    					}
    				}
    			}
    			else
    			{
    				//
    				// Now copy the last piece of the string.
    				//
    				for(i32Buf = 0; i32Buf < (ui32Size - i32Idx); i32Buf++)
    				{
    					//
    					// Copy the string to the output buffer.
    					//
    					pcData[i32Idx + i32Buf] = g_pui8StringData[ui32Offset +
    															   i32Buf];
    
    					//
    					// If a null is hit then terminate the copy.
    					//
    					if(pcData[i32Idx + i32Buf] == 0)
    					{
    						break;
    					}
    				}
    			}
    
    			//
    			// If we had not copied any characters before hitting this case,
    			// initialize the output pointer (this keeps the code at the end of
    			// the function that returns the length happy).  This will be the
    			// case if we are using an uncompressed string table.
    			//
    			if(!pui8BufferOut)
    			{
    				pui8BufferOut = (uint8_t *)pcData + (i32Idx + i32Buf);
    			}
    
            }
            i32Pos--;
        }
    
        //
        // Return the number of bytes copied into the output buffer.
        //
        if(pui8BufferOut)
        {
            ui32Len = ((uint32_t)pui8BufferOut - (uint32_t)pcData);
    
            //
            // Null terminate the string if there is room.
            //
            if(ui32Len < ui32Size)
            {
                pcData[ui32Len] = 0;
            }
        }
        else
        {
            ui32Len = 0;
        }
    
        return(ui32Len);
    }
    

  • Hello Steve

    Thanks for reporting the issue. It will not be possible for us to make the change in the next TivaWare release, but we will document the same in the bug tracking system