| /* |
| ******************************************************************************** |
| * * |
| * 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; |
| } |