blob: 23bc3e4b0ee75bd7eb6893bc0deab345c5a1f439 [file] [log] [blame]
/*
********************************************************************************
* *
* COPYRIGHT: *
* (C) Copyright International Business Machines Corporation, 1998 *
* Licensed Material - Program-Property of IBM - All Rights Reserved. *
* US Government Users Restricted Rights - Use, duplication, or disclosure *
* restricted by GSA ADP Schedule Contract with IBM Corp. *
* *
********************************************************************************
*
*
* uconv_io.c:
* initializes global variables and defines functions pertaining to file access,
* and name resolution aspect of the library.
********************************************************************************
*/
#include "utypes.h"
#include "umutex.h"
#include "filestrm.h"
#include "cstring.h"
#include "cmemory.h"
#include "uhash.h"
#include "ucmp8.h"
#include "ucmp16.h"
#include "ucnv_bld.h"
#include "ucnv_io.h"
#include "uloc.h"
static void doSetupAliasTableAndAvailableConverters (FileStream * converterFile,
UErrorCode * err);
static char *_convertDataDirectory = NULL;
/*Initializes Global Variables */
static UHashtable *ALIASNAMES_HASHTABLE = NULL;
char **AVAILABLE_CONVERTERS_NAMES = NULL;
int32_t AVAILABLE_CONVERTERS = 0;
/* Remove all characters followed by '#'
*/
char *
removeComments (char *line)
{
char *pound = icu_strchr (line, '#');
if (pound != NULL)
*pound = '\0';
return line;
}
/*Returns uppercased string */
char *
strtoupper (char *name)
{
int32_t i = 0;
while (name[i] = icu_toupper (name[i]))
i++;
return name;
}
/* Returns true in c is a in set 'setOfChars', false otherwise
*/
bool_t
isInSet (char c, const char *setOfChars)
{
uint8_t i = 0;
while (setOfChars[i] != '\0')
{
if (c == setOfChars[i++])
return TRUE;
}
return FALSE;
}
/* Returns pointer to the next non-whitespace (or non-separator)
*/
int32_t
nextTokenOffset (const char *line, const char *separators)
{
int32_t i = 0;
while (line[i] && isInSet (line[i], separators))
i++;
return i;
}
/* Returns pointer to the next token based on the set of separators
*/
char *
getToken (char *token, char *line, const char *separators)
{
int32_t i = nextTokenOffset (line, separators);
int8_t j = 0;
while (line[i] && (!isInSet (line[i], separators)))
token[j++] = line[i++];
token[j] = '\0';
return line + i;
}
/* this function is called only if ((ALIASNAMES_HASHTABLE == NULL) ||
* (AVAILABLE_CONVERTERS_NAMES == NULL)) it builds a hashtable containing
* all the "real" table names (filenames), keyed-off of the aliases and
* the real-names themselves.
* Also builds an array of char **, that point to the allocated memory
* for each actual names in the Hashtable.
* That array is used in T_UnicodeConverter_getAvailableNames.
*/
void
setupAliasTableAndAvailableConverters (UErrorCode * err)
{
char fullFileName[MAX_FULL_FILE_NAME_LENGTH];
FileStream *converterFile = NULL;
if (FAILURE (*err))
return;
icu_strcpy (fullFileName, uloc_getDataDirectory ());
icu_strcat (fullFileName, CONVERTER_FILE_NAME);
converterFile = T_FileStream_open (fullFileName, "r");
if (converterFile == NULL)
{
*err = FILE_ACCESS_ERROR;
}
else
{
doSetupAliasTableAndAvailableConverters (converterFile, err);
T_FileStream_close (converterFile);
}
return;
}
/* this function is only to be called by setupAliasTableAndAvailableConverters
*/
void
doSetupAliasTableAndAvailableConverters (FileStream * converterFile, UErrorCode * err)
{
Mutex *convertrsFileOpenMutex = NULL;
char myLine[MAX_LINE_TEXT];
char *line = myLine;
char actualNameToken[MAX_CONVERTER_NAME_LENGTH];
char aliasNameToken[MAX_CONVERTER_NAME_LENGTH];
char *toBeHashed = NULL;
UHashtable *myALIASNAMES_HASHTABLE = NULL;
char **myAVAILABLE_CONVERTERS_NAMES = NULL;
int32_t myAVAILABLE_CONVERTERS = 0;
/*We need to do the initial work of setting everything */
myALIASNAMES_HASHTABLE = uhash_open ((UHashFunction)uhash_hashIString, err);
if (FAILURE (*err))
return;
if (myALIASNAMES_HASHTABLE == NULL)
return;
while (T_FileStream_readLine (converterFile, line, MAX_LINE_TEXT))
{
removeComments (line);
if (line[nextTokenOffset (line, SPACE_SEPARATORS)] != '\0') /*Skips Blank lines */
{
line = getToken (actualNameToken, line, SPACE_SEPARATORS);
toBeHashed = (char *) icu_malloc ((icu_strlen (actualNameToken) + 1) * sizeof (char));
if (toBeHashed == NULL)
{
*err = MEMORY_ALLOCATION_ERROR;
return;
}
icu_strcpy (toBeHashed, actualNameToken);
myAVAILABLE_CONVERTERS_NAMES = (char **) icu_realloc (myAVAILABLE_CONVERTERS_NAMES,
(myAVAILABLE_CONVERTERS + 1) * sizeof (char *));
if (myAVAILABLE_CONVERTERS_NAMES == NULL)
{
*err = MEMORY_ALLOCATION_ERROR;
return;
}
myAVAILABLE_CONVERTERS_NAMES[myAVAILABLE_CONVERTERS++] = toBeHashed;
uhash_put (myALIASNAMES_HASHTABLE, toBeHashed, err);
while (line[nextTokenOffset (line, SPACE_SEPARATORS)] != '\0')
{
line = getToken (aliasNameToken, line, SPACE_SEPARATORS);
uhash_putKey (myALIASNAMES_HASHTABLE,
uhash_hashIString (aliasNameToken),
toBeHashed,
err);
}
if (FAILURE (*err))
return;
}
}
/*If another thread has already created the hashtable and array, we need to free */
if ((ALIASNAMES_HASHTABLE != NULL) || (AVAILABLE_CONVERTERS_NAMES != NULL))
{
while (myAVAILABLE_CONVERTERS > 0)
{
icu_free (myAVAILABLE_CONVERTERS_NAMES[--myAVAILABLE_CONVERTERS]);
}
icu_free (myAVAILABLE_CONVERTERS_NAMES);
uhash_close (myALIASNAMES_HASHTABLE);
}
else
{
umtx_lock (NULL);
ALIASNAMES_HASHTABLE = myALIASNAMES_HASHTABLE;
AVAILABLE_CONVERTERS_NAMES = myAVAILABLE_CONVERTERS_NAMES;
AVAILABLE_CONVERTERS = myAVAILABLE_CONVERTERS;
umtx_unlock (NULL);
}
return;
}
/* resolveName takes a table alias name and fills in the actual name used internally.
* it returns a TRUE if the name was found (table supported) returns FALSE otherwise
*/
bool_t
resolveName (char *realName, const char *alias)
{
int32_t i = 0;
bool_t found = FALSE;
char *actualName = NULL;
UErrorCode err = ZERO_ERROR;
/*Lazy evaluates the Alias hashtable */
if (ALIASNAMES_HASHTABLE == NULL)
setupAliasTableAndAvailableConverters (&err);
if (FAILURE (err))
return FALSE;
actualName = (char *) uhash_get (ALIASNAMES_HASHTABLE, uhash_hashIString (alias));
if (actualName != NULL)
{
icu_strcpy (realName, actualName);
found = TRUE;
}
return found;
}
/*Higher level function, takes in an alias name
*and returns a file pointer of the table file
*Will return NULL if the file isn't found for
*any given reason (file not there, name not in
*"convrtrs.txt"
*/
FileStream *
openConverterFile (const char *name)
{
char actualFullFilenameName[MAX_FULL_FILE_NAME_LENGTH];
FileStream *tableFile = NULL;
icu_strcpy (actualFullFilenameName, uloc_getDataDirectory ());
if (resolveName (actualFullFilenameName + icu_strlen (actualFullFilenameName), name))
{
icu_strcat (actualFullFilenameName, CONVERTER_FILE_EXTENSION);
tableFile = T_FileStream_open (actualFullFilenameName, "rb");
}
return tableFile;
}