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() */