uint32_t FF_FindEntryInDir()

in ff_dir.c [301:688]


    uint32_t FF_FindEntryInDir( FF_IOManager_t * pxIOManager,
                                FF_FindParams_t * pxFindParams,
                                const FF_T_WCHAR * pcName,
                                uint8_t pa_Attrib,
                                FF_DirEnt_t * pxDirEntry,
                                FF_Error_t * pxError )
#else
    uint32_t FF_FindEntryInDir( FF_IOManager_t * pxIOManager,
                                FF_FindParams_t * pxFindParams,
                                const char * pcName,
                                uint8_t pa_Attrib,
                                FF_DirEnt_t * pxDirEntry,
                                FF_Error_t * pxError )
#endif /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
{
    FF_FetchContext_t xFetchContext;
/* const pointer to read from pBuffer */
    const uint8_t * src = NULL;

/* As we're walking through a directory, we might as well
 * find the first free entry to help FF_FindFreeDirent( )
 * The result will be stored in 'pxFindParams->lFreeEntry' */
    BaseType_t entriesNeeded;
    BaseType_t freeCount = 0;
    FF_Error_t xError;

/* If the file name fits into a short file name
 * then the existence of that short file name will be checked as well. */
    BaseType_t testShortname;
    uint32_t xResult = 0ul;

    #if ( ffconfigUNICODE_UTF8_SUPPORT == 1 )
        int32_t utf8Error;
    #endif

    #if ( ffconfigLFN_SUPPORT != 0 )
        #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
            FF_T_WCHAR * pcCurPtr;  /* Pointer to store a LFN. */
            FF_T_WCHAR * pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName );
        #else
            char * pcCurPtr;    /* Pointer to store a LFN. */
            char * pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName );
        #endif /* ffconfigUNICODE_UTF16_SUPPORT */

        uint16_t lfnItem = 0;
        uint8_t ucCheckSum = 0;
        BaseType_t xLFNCount = 0;
        BaseType_t xLFNTotal = 0;
        uint8_t lastAttrib;

        BaseType_t xIndex;
    #endif /* ffconfigLFN_SUPPORT */

    #if ( ffconfigLFN_SUPPORT != 0 )
        {
            #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
                BaseType_t NameLen = ( BaseType_t ) wcslen( ( const char * ) pcName );
            #else
                BaseType_t NameLen = ( BaseType_t ) strlen( ( const char * ) pcName );
            #endif
            /* Find enough places for the LFNs and the ShortName. */
            entriesNeeded = ( uint8_t ) ( ( NameLen + 12 ) / 13 ) + 1;
        }
    #else
        {
            entriesNeeded = 1;
        }
    #endif /* ffconfigLFN_SUPPORT */

    if( ( pxFindParams->ulFlags & FIND_FLAG_FITS_SHORT_OK ) == FIND_FLAG_FITS_SHORT_OK )
    {
        testShortname = pdTRUE;
    }
    else
    {
        testShortname = pdFALSE;
    }

    pxDirEntry->ucAttrib = 0;

    if( ( pxFindParams->ulFlags & FIND_FLAG_CREATE_FLAG ) != 0 )
    {
        /* A file is to be created: keep track of the first free entry big enough
         * to hold this file name. */
        pxFindParams->lFreeEntry = -1;
    }
    else
    {
        pxFindParams->lFreeEntry = 0;
    }

    xError = FF_InitEntryFetch( pxIOManager, pxFindParams->ulDirCluster, &xFetchContext );

    if( FF_isERR( xError ) == pdFALSE )
    {
        for( pxDirEntry->usCurrentItem = 0; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ )
        {
            if( ( src == NULL ) ||
                ( src >= xFetchContext.pxBuffer->pucBuffer + ( pxIOManager->usSectorSize - FF_SIZEOF_DIRECTORY_ENTRY ) ) )
            {
                xError = FF_FetchEntryWithContext( pxIOManager, pxDirEntry->usCurrentItem, &xFetchContext, NULL );

                if( FF_isERR( xError ) != pdFALSE )
                {
                    break;
                }

                src = xFetchContext.pxBuffer->pucBuffer;
            }
            else
            {
                /* Advance 32 bytes. */
                src += FF_SIZEOF_DIRECTORY_ENTRY;
            }

            if( FF_isEndOfDir( src ) )
            {
                /* 0x00 end-of-dir. */
                break;
            }

            if( FF_isDeleted( src ) )
            {
                /* Entry not used or deleted. */
                pxDirEntry->ucAttrib = 0;

                if( ( pxFindParams->lFreeEntry < 0 ) && ( ++freeCount == entriesNeeded ) )
                {
                    /* Remember the beginning entry in the sequential sequence. */
                    pxFindParams->lFreeEntry = ( pxDirEntry->usCurrentItem - ( entriesNeeded - 1 ) );
                }

                continue;
            }

            /* The current entry is in use, so reset the free-entry-counter */
            freeCount = 0;
            #if ( ffconfigLFN_SUPPORT != 0 )
                {
                    lastAttrib = pxDirEntry->ucAttrib;
                }
            #endif

            pxDirEntry->ucAttrib = FF_getChar( src, FF_FAT_DIRENT_ATTRIB );

            if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN )
            {
                /* LFN Processing. */
                #if ( ffconfigLFN_SUPPORT != 0 )
                    {
                        if( ( xLFNCount == 0 ) || ( ( lastAttrib & FF_FAT_ATTR_LFN ) != FF_FAT_ATTR_LFN ) )
                        {
                            xLFNTotal = xLFNCount = ( BaseType_t ) ( src[ 0 ] & ~0x40 );
                            lfnItem = pxDirEntry->usCurrentItem;
                            ucCheckSum = FF_getChar( src, FF_FAT_LFN_CHECKSUM );
                            pcLastPtr[ -1 ] = '\0';
                        }

                        if( xLFNCount != 0 )
                        {
                            xLFNCount--;
                            pcCurPtr = pxDirEntry->pcFileName + ( xLFNCount * 13 );

                            /*
                             *  This section needs to extract the name and do the comparison
                             *  dependent on UNICODE settings in the FreeRTOSFATConfig.h file.
                             */
                            #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
                                {
                                    /* Add UTF-16 Routine here. */
                                    /* Copy first 5 UTF-16 chars ( 10 bytes ). */
                                    memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_1 ], 10 );
                                    /* Increment Filename pointer 5 utf16 chars. */
                                    pcCurPtr += 5;

                                    /* Copy next 6 chars ( 12 bytes ). */
                                    memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_2 ], 12 );
                                    pcCurPtr += 6;

                                    /* You're getting the idea by now! */
                                    memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_3 ], 4 );
                                    pcCurPtr += 2;
                                } /* ffconfigUNICODE_UTF16_SUPPORT */
                            #elif ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
                                {
                                    /* UTF-8 Routine here. */
                                    for( xIndex = 0; ( xIndex < 5 ) && ( pcCurPtr < pcLastPtr ); xIndex++ )
                                    {
                                        /* Was there a surrogate sequence? -- Add handling here. */
                                        utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_1 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr );

                                        if( utf8Error > 0 )
                                        {
                                            pcCurPtr += utf8Error;
                                        }
                                        else
                                        {
                                            if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE )
                                            {
                                                /* Handle potential surrogate sequence across entries. */
                                            }
                                        }
                                    }

                                    for( xIndex = 0; xIndex < 6 && pcCurPtr < pcLastPtr; xIndex++ )
                                    {
                                        /* Was there a surrogate sequence? -- To add handling here. */
                                        utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_2 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr );

                                        if( utf8Error > 0 )
                                        {
                                            pcCurPtr += utf8Error;
                                        }
                                        else
                                        {
                                            if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE )
                                            {
                                                /* Handle potential surrogate sequence across entries. */
                                            }
                                        }
                                    }

                                    for( xIndex = 0; xIndex < 2 && pcCurPtr < pcLastPtr; xIndex++ )
                                    {
                                        /* Was there a surrogate sequence? -- To add handling here. */
                                        utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_3 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr );

                                        if( utf8Error > 0 )
                                        {
                                            pcCurPtr += utf8Error;
                                        }
                                        else
                                        {
                                            if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE )
                                            {
                                                /* Handle potential surrogate sequence across entries. */
                                            }
                                        }
                                    }
                                } /* ffconfigUNICODE_UTF8_SUPPORT */
                            #else /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
                                { /* use ASCII notation. */
                                    for( xIndex = 0; ( xIndex < 10 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )
                                    {
                                        *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_1 + xIndex ];
                                    }

                                    for( xIndex = 0; ( xIndex < 12 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )
                                    {
                                        *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_2 + xIndex ];
                                    }

                                    for( xIndex = 0; ( xIndex < 4 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 )
                                    {
                                        *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_3 + xIndex ];
                                    }
                                }
                            #endif /* ( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && !( ffconfigUNICODE_UTF8_SUPPORT == 0 ) */

                            if( ( xLFNCount == xLFNTotal - 1 ) && ( pcCurPtr < pcLastPtr ) )
                            {
                                *pcCurPtr = '\0'; /* Important when name len is multiple of 13. */
                            }
                        } /* if( xLFNCount ) */
                    }
                #endif /* ffconfigLFN_SUPPORT */
                continue;
            }

            if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_VOLID ) == FF_FAT_ATTR_VOLID )
            {
                #if ( ffconfigLFN_SUPPORT != 0 )
                    {
                        xLFNTotal = 0;
                    }
                #endif /* ffconfigLFN_SUPPORT */
                continue;
            }

            #if ( ffconfigLFN_SUPPORT != 0 )
                if( ( xLFNTotal == 0 ) || ( ucCheckSum != FF_CreateChkSum( src ) ) )
            #endif /* ffconfigLFN_SUPPORT */
            {
                /* This entry has only a short name, or the checksum isn't correct
                 * Use the short name for comparison */
                memcpy( pxDirEntry->pcFileName, src, 11 );
                FF_ProcessShortName( ( char * ) pxDirEntry->pcFileName );
                #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
                    {
                        /* FileName now contains a 8-bit short name
                         * Expand it to a FF_T_WCHAR string. */
                        FF_ShortNameExpand( pxDirEntry->pcFileName );
                    }
                #endif /* ffconfigUNICODE_UTF16_SUPPORT */
                #if ( ffconfigLFN_SUPPORT != 0 )
                    {
                        xLFNTotal = 0;
                    }
                #endif /* ffconfigLFN_SUPPORT */
            }

            /* This function FF_FindEntryInDir( ) is either called with
            * pa_Attrib==0 or with pa_Attrib==FF_FAT_ATTR_DIR
            * In the last case the caller is looking for a directory */
            if( ( pxDirEntry->ucAttrib & pa_Attrib ) == pa_Attrib )
            {
                if( testShortname )
                {
                    /* Both strings are stored in the directory format
                     * e.g. "README  TXT", without a dot */
                    if( memcmp( src, pxFindParams->pcEntryBuffer, 11 ) == 0 )
                    {
                        pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_CHECKED | FIND_FLAG_SHORTNAME_FOUND;
                    }
                }

                #if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
                    if( wcsicmp( ( const char * ) pcName, ( const char * ) pxDirEntry->pcFileName ) == 0 )
                #else
                    if( FF_stricmp( ( const char * ) pcName, ( const char * ) pxDirEntry->pcFileName ) == 0 )
                #endif /* ffconfigUNICODE_UTF16_SUPPORT */
                {
                    /* Finally get the complete information. */
                    #if ( ffconfigLFN_SUPPORT != 0 )
                        if( xLFNTotal )
                        {
                            xError = FF_PopulateLongDirent( pxIOManager, pxDirEntry, ( uint16_t ) lfnItem, &xFetchContext );

                            if( FF_isERR( xError ) )
                            {
                                break;
                            }
                        }
                        else
                    #endif /* ffconfigLFN_SUPPORT */
                    {
                        FF_PopulateShortDirent( pxIOManager, pxDirEntry, src );
                        /* HT: usCurrentItem wasn't increased here. */
                        pxDirEntry->usCurrentItem++;
                    }

                    /* Object found, the cluster number will be returned. */
                    xResult = pxDirEntry->ulObjectCluster;
                    break;
                }
            }

            #if ( ffconfigLFN_SUPPORT != 0 )
                {
                    xLFNTotal = 0;
                }
            #endif
        }   /* for( ; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ ) */

        {
            FF_Error_t xTempError;
            xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext );

            if( FF_isERR( xError ) == pdFALSE )
            {
                xError = xTempError;
            }
        }
    } /* if( FF_isERR( xError ) == pdFALSE ) */

    if( FF_isERR( xError ) == pdFALSE )
    {
        /* If a free entry wasn't found yet, put it to the current (last) item */
        if( pxFindParams->lFreeEntry < 0 )
        {
            pxFindParams->lFreeEntry = pxDirEntry->usCurrentItem;
        }

        /* If we were checking the existence of the short-name
         * set the Checked flag now */
        if( testShortname )
        {
            pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_CHECKED;
        }
    }

    if( pxError != NULL )
    {
        *pxError = xError;
    }

    return xResult;
}   /* FF_FindEntryInDir() */