Files
filex/common/src/fx_unicode_directory_search.c
T
Frédéric Desbiens 61b0b06c3e Updated copyright headers and removed revision history
* Updated version number constants

* Updated copyright headers and removed revision history
2026-03-05 08:39:33 +01:00

494 lines
18 KiB
C

/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
* Copyright (c) 2026-present Eclipse ThreadX contributors
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** FileX Component */
/** */
/** Unicode */
/** */
/**************************************************************************/
/**************************************************************************/
#define FX_SOURCE_CODE
/* Include necessary system files. */
#include "fx_api.h"
#include "fx_unicode.h"
#include "fx_utility.h"
#ifndef FX_NO_LOCAL_PATH
FX_LOCAL_PATH_SETUP
#endif
/* Define several Unicode working arrays... This keeps the data structures
off the local stack. */
UCHAR _fx_unicode_temp_long_file_name[FX_MAX_LONG_NAME_LEN];
UCHAR _fx_unicode_search_name[FX_MAX_LONG_NAME_LEN * 2];
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _fx_unicode_directory_search PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function searches for the specified unicode or short name. */
/* */
/* Note: The buffer of short_name and unicode_name must be valid to */
/* fill search result. When short_name is a zero length string, search */
/* is based on unicode string (terminated with NULL). If it's found */
/* the short name is written back to buffer of short_name. In this case*/
/* unicode_name_buffer_length is ignored and short_name_buffer_length */
/* must not be zero to specify the buffer length. If buffer is too */
/* smallfor the result, overflow characters and NULL-terminator are cut*/
/* off. When short_name is a valid string, search is based on */
/* short_name (terminated with NULL). If it's found the unicode name is*/
/* written back to buffer of unicode_name. In this case */
/* short_name_buffer_length is ignored and unicode_name_buffer_length */
/* must not be zero to specify the unicode buffer length. If buffer is */
/* too small for the result, overflow characters are cut off but */
/* NULL-terminator is kept. */
/* */
/* INPUT */
/* */
/* media_ptr Pointer to media */
/* short_name Pointer to short name */
/* short_name_buffer_length Buffer length for short name */
/* unicode_name Pointer to Unicode name */
/* unicode_name_length Unicode name length */
/* unicode_name_buffer_length Buffer length for Unicode name*/
/* */
/* OUTPUT */
/* */
/* Completion Status */
/* */
/* CALLS */
/* */
/* _fx_unicode_directory_entry_read Read a full unicode directory */
/* entry */
/* _fx_utility_FAT_entry_read Read a FAT entry */
/* */
/* CALLED BY */
/* */
/* Unicode Utilities */
/* */
/**************************************************************************/
UINT _fx_unicode_directory_search(FX_MEDIA *media_ptr, FX_DIR_ENTRY *entry_ptr,
UCHAR *short_name, ULONG short_name_buffer_length,
UCHAR *unicode_name, ULONG *unicode_name_length, ULONG unicode_name_buffer_length)
{
ULONG i, j;
UINT status, found;
ULONG cluster, next_cluster = 0;
ULONG directory_size;
FX_DIR_ENTRY search_dir;
FX_DIR_ENTRY *search_dir_ptr;
ULONG unicode_search_length;
ULONG local_unicode_name_length;
CHAR unicode_to_short_name[13];
CHAR *short_name_ptr;
/* Setup temp unicode name length. */
local_unicode_name_length = *unicode_name_length;
#ifndef FX_MEDIA_STATISTICS_DISABLE
/* Increment the number of directory search requests. */
media_ptr -> fx_media_directory_searches++;
#endif
/* Set the initial search directory to the current working
directory - if there is one. */
/* First check for a local path pointer stored in the thread control block. This
is only available in ThreadX Version 4 and above. */
#ifndef FX_NO_LOCAL_PATH
if (_tx_thread_current_ptr -> tx_thread_filex_ptr)
{
/* Determine if the local directory is not the root directory. */
if (((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_directory.fx_dir_entry_name[0])
{
/* Start at the current working directory of the media. */
search_dir = ((FX_PATH *)_tx_thread_current_ptr -> tx_thread_filex_ptr) -> fx_path_directory;
/* Set the internal pointer to the search directory as well. */
search_dir_ptr = &search_dir;
}
else
{
/* We are searching in the root directory. */
search_dir_ptr = FX_NULL;
}
}
else
#endif
if (media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0])
{
/* Start at the current working directory of the media. */
search_dir = media_ptr -> fx_media_default_path.fx_path_directory;
/* Set the internal pointer to the search directory as well. */
search_dir_ptr = &search_dir;
}
else
{
/* The current default directory is the root so just set the
search directory pointer to NULL. */
search_dir_ptr = FX_NULL;
}
/* Calculate the directory size. */
if (search_dir_ptr)
{
/* Ensure that the search directory's last search cluster is cleared. */
search_dir_ptr -> fx_dir_entry_last_search_cluster = 0;
/* Calculate the directory size by counting the allocated
clusters for it. */
i = 0;
cluster = search_dir_ptr -> fx_dir_entry_cluster;
while ((cluster >= FX_FAT_ENTRY_START) && (cluster < media_ptr -> fx_media_fat_reserved))
{
/* Increment the cluster count. */
i++;
/* Read the next FAT entry. */
status = _fx_utility_FAT_entry_read(media_ptr, cluster, &next_cluster);
/* Check the return status. */
if (status != FX_SUCCESS)
{
/* Return the bad status. */
return(status);
}
/* Check for error situation. */
if ((cluster == next_cluster) || (i > media_ptr -> fx_media_total_clusters))
{
/* Return the bad status. */
return(FX_FAT_READ_ERROR);
}
cluster = next_cluster;
}
/* Now we can calculate the directory size. */
directory_size = (((ULONG)media_ptr -> fx_media_bytes_per_sector) *
((ULONG)media_ptr -> fx_media_sectors_per_cluster) * i) /
(ULONG)FX_DIR_ENTRY_SIZE;
/* Also save this in the directory entry so we don't have to
calculate it later. */
search_dir_ptr -> fx_dir_entry_file_size = directory_size;
}
else
{
/* Directory size is the number of entries in the root directory. */
directory_size = (ULONG)media_ptr -> fx_media_root_directory_entries;
}
/* Determine if we are searching for a short file name or a unicode file name. */
if (short_name[0] == 0)
{
/* If the unicode name fit into short name length, covert the Unicode to ASCII if possible. */
if (local_unicode_name_length <= 13)
{
for (j = 0; j < local_unicode_name_length; j++)
{
if ((unicode_name[j * 2] <= 0x7F) && (unicode_name[j * 2 + 1] == 0))
{
unicode_to_short_name[j] = (CHAR)unicode_name[j * 2];
if ((unicode_to_short_name[j] >= 'a') && (unicode_to_short_name[j] <= 'z'))
{
/* Lower case, convert to upper case! */
unicode_to_short_name[j] = (CHAR)((INT)unicode_to_short_name[j] - 0x20);
}
}
else
{
unicode_to_short_name[0] = 0;
break;
}
}
}
else
{
unicode_to_short_name[0] = 0;
}
}
else
{
unicode_to_short_name[0] = 0;
}
/* Loop through entries in the directory. Yes, this is a
linear search! */
i = 0;
do
{
/* Read an entry from the directory. */
status = _fx_unicode_directory_entry_read(media_ptr, search_dir_ptr, &i, entry_ptr, &_fx_unicode_search_name[0], &unicode_search_length);
i++;
/* Check for error status. */
if (status != FX_SUCCESS)
{
return(status);
}
/* Determine if this is an empty entry. */
if (((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_FREE) && (entry_ptr -> fx_dir_entry_short_name[0] == 0))
{
continue;
}
/* Determine if this is the last directory entry. */
if ((UCHAR)entry_ptr -> fx_dir_entry_name[0] == (UCHAR)FX_DIR_ENTRY_DONE)
{
break;
}
/* Determine if there is a short name to match. */
if (unicode_to_short_name[0])
{
/* Get the short name pointer. */
if (entry_ptr -> fx_dir_entry_short_name[0])
{
short_name_ptr = entry_ptr -> fx_dir_entry_short_name;
}
else
{
short_name_ptr = entry_ptr -> fx_dir_entry_name;
}
for (j = 0; j < local_unicode_name_length; j++)
{
/* Compare characters. */
if (short_name_ptr[j] != unicode_to_short_name[j])
{
break;
}
}
if (j == local_unicode_name_length)
{
/* Only the 1st 13 bytes or the buffer length is copied, whichever is smaller. */
if (short_name_buffer_length > 13)
{
short_name_buffer_length = 13;
}
/* The names match, copy the short name into the destination. */
for (j = 0; j < short_name_buffer_length; j++)
{
short_name[j] = (UCHAR)short_name_ptr[j];
}
/* Return success to caller. */
return(FX_SUCCESS);
}
}
/* Determine if this is not a unicode name. */
if (unicode_search_length == 0)
{
continue;
}
/* Determine if we are searching for a short file name or a unicode file name. */
if (short_name[0])
{
/* We have a short name and need a unicode name. Compare the short name against the short name in
the directory entry for a match. */
found = FX_TRUE;
for (j = 0; j < 12; j++)
{
/* Compare characters... */
if (entry_ptr -> fx_dir_entry_short_name[0])
{
/* Yes, the return name is in the short name field... compare against it! */
if (short_name[j] != (UCHAR)entry_ptr -> fx_dir_entry_short_name[j])
{
found = FX_FALSE;
break;
}
}
else
{
/* No, the return name is in the name field... compare against it! */
if (short_name[j] != (UCHAR)entry_ptr -> fx_dir_entry_name[j])
{
found = FX_FALSE;
break;
}
}
/* Are we done? */
if (short_name[j] == (UCHAR)FX_NULL)
{
break;
}
}
/* One final compare to see if we have a match. */
if ((found == FX_FALSE) || ((j == 12) && (short_name[12] != 0)))
{
continue;
}
/* A match was found so copy the unicode name and length and return. */
/* Copy the length. */
*unicode_name_length = unicode_search_length;
/* Check if the name fit in the buffer. */
if (unicode_name_buffer_length < (unicode_search_length + 1) * 2)
{
unicode_search_length = (unicode_name_buffer_length - 2) / 2;
}
/* Copy the unicode name. */
for (j = 0; j < unicode_search_length * 2; j++)
{
/* Copy one unicode character to the destination... */
unicode_name[j] = _fx_unicode_search_name[j];
}
/* Make sure there is a NULL in the destination. */
unicode_name[j] = (UCHAR)0;
unicode_name[j + 1] = (UCHAR)0;
/* Return successful completion. */
return(FX_SUCCESS);
}
else
{
/* Determine if this is the correct unicode name. */
if (unicode_search_length != local_unicode_name_length)
{
continue;
}
/* Compare the unicode search name with the requested unicode name. */
for (j = 0; j < (local_unicode_name_length * 2); j = j + 2)
{
/* Compare bytes of each unicode name. */
if (unicode_name[j] != _fx_unicode_search_name[j])
{
/* Not match, Check if the character is in ASCII range. */
if ((_fx_unicode_search_name[j + 1] == 0) && (unicode_name[j + 1] == 0))
{
/* Check if it is case mismatch. */
if ((unicode_name[j]) >= 'a' && (unicode_name[j] <= 'z'))
{
if ((unicode_name[j] - 0x20) == _fx_unicode_search_name[j])
{
continue;
}
}
if ((_fx_unicode_search_name[j]) >= 'a' && (_fx_unicode_search_name[j] <= 'z'))
{
if ((_fx_unicode_search_name[j] - 0x20) == unicode_name[j])
{
continue;
}
}
}
break;
}
/* Compare the next byte. */
if (unicode_name[j + 1] != _fx_unicode_search_name[j + 1])
{
break;
}
}
/* Determine if the names do not match. */
if (j != (local_unicode_name_length * 2))
{
continue;
}
/* Otherwise, the names match, copy the short name into the destination. */
/* Only the 1st 13 bytes or the buffer length is copied, whichever is smaller. */
if (short_name_buffer_length > 13)
{
short_name_buffer_length = 13;
}
for (j = 0; j < short_name_buffer_length; j++)
{
/* Copy a character. */
if (entry_ptr -> fx_dir_entry_short_name[0])
{
short_name[j] = (UCHAR)entry_ptr -> fx_dir_entry_short_name[j];
}
else
{
short_name[j] = (UCHAR)entry_ptr -> fx_dir_entry_name[j];
}
}
/* Return success to caller. */
return(FX_SUCCESS);
}
} while (i < directory_size);
/* Return not found. */
return(FX_NOT_FOUND);
}