From c786b21d5234a0f6181ceb4f3dd7c1af59a95d5b Mon Sep 17 00:00:00 2001 From: Vladimir Weinstein Date: Mon, 15 May 2000 18:39:17 +0000 Subject: [PATCH] ICU-184 resource data files in memory mapped format (initial revision) X-SVN-Rev: 1365 --- icu4c/source/common/Makefile.in | 4 +- icu4c/source/common/common.dsp | 26 +- icu4c/source/common/locid.cpp | 31 +- icu4c/source/common/putil.c | 7 +- icu4c/source/common/rbdata.h | 1 + icu4c/source/common/resbund.cpp | 1463 +++++++---------------- icu4c/source/common/ucnv.c | 8 +- icu4c/source/common/uloc.c | 91 +- icu4c/source/common/unicode/resbund.h | 383 +++--- icu4c/source/common/unicode/ures.h | 191 ++- icu4c/source/common/unicode/utypes.h | 1 + icu4c/source/common/uresbund.c | 1107 +++++++++++++++++ icu4c/source/common/uresdata.c | 261 +++- icu4c/source/common/uresdata.h | 67 +- icu4c/source/common/uresimp.h | 91 ++ icu4c/source/i18n/calendar.cpp | 22 +- icu4c/source/i18n/datefmt.cpp | 11 +- icu4c/source/i18n/dcfmtsym.cpp | 22 +- icu4c/source/i18n/decimfmt.cpp | 9 +- icu4c/source/i18n/dtfmtsym.cpp | 93 +- icu4c/source/i18n/i18n.dsp | 432 +++++++ icu4c/source/i18n/numfmt.cpp | 21 +- icu4c/source/i18n/smpdtfmt.cpp | 32 +- icu4c/source/i18n/tblcoll.cpp | 54 +- icu4c/source/i18n/translit.cpp | 51 +- icu4c/source/i18n/unicode/dtfmtsym.h | 3 + icu4c/source/test/cintltst/Makefile.in | 2 +- icu4c/source/test/cintltst/cintltst.c | 4 +- icu4c/source/test/cintltst/cintltst.dsp | 9 + icu4c/source/test/cintltst/creststn.c | 790 ++++++++++++ icu4c/source/test/cintltst/creststn.h | 53 + icu4c/source/test/cintltst/cutiltst.c | 2 + icu4c/source/test/intltest/Makefile.in | 2 +- icu4c/source/test/intltest/intltest.dsp | 23 +- icu4c/source/test/intltest/itutil.cpp | 15 +- icu4c/source/test/intltest/restsnew.cpp | 812 +++++++++++++ icu4c/source/test/intltest/restsnew.h | 44 + icu4c/source/tools/Makefile.in | 24 +- icu4c/source/tools/genrb/Makefile.in | 76 +- icu4c/source/tools/genrb/genrb.c | 250 ++-- icu4c/source/tools/genrb/genrb.dsp | 26 +- icu4c/source/tools/genrb/genrb.dsw | 27 + icu4c/source/tools/genrb/list.c | 160 ++- icu4c/source/tools/genrb/list.h | 10 +- icu4c/source/tools/genrb/parse.c | 327 ++--- icu4c/source/tools/genrb/parse.h | 2 +- icu4c/source/tools/genrb/rblist.c | 160 +-- icu4c/source/tools/genrb/rblist.h | 15 +- icu4c/source/tools/genrb/read.c | 77 +- icu4c/source/tools/genrb/read.h | 9 +- icu4c/source/tools/genrb/write.c | 59 +- icu4c/source/tools/makedata.mak | 84 +- 52 files changed, 5533 insertions(+), 2011 deletions(-) create mode 100644 icu4c/source/common/uresbund.c create mode 100644 icu4c/source/common/uresimp.h create mode 100644 icu4c/source/test/cintltst/creststn.c create mode 100644 icu4c/source/test/cintltst/creststn.h create mode 100644 icu4c/source/test/intltest/restsnew.cpp create mode 100644 icu4c/source/test/intltest/restsnew.h diff --git a/icu4c/source/common/Makefile.in b/icu4c/source/common/Makefile.in index 49eaa45800b..6e5a0079fe6 100644 --- a/icu4c/source/common/Makefile.in +++ b/icu4c/source/common/Makefile.in @@ -73,10 +73,12 @@ cpputils.o cstring.o dcmpdata.o digitlst.o filestrm.o locid.o locmap.o \ mutex.o normlzr.o putil.o rbcache.o resbund.o schriter.o scsu.o \ uchar.o uchriter.o ucmp8.o ucmp16.o ucmp32.o ucnv.o ucnv_bld.o \ ucnv_cnv.o ucnv_err.o ucnv_io.o uhash.o uhash_us.o uloc.o unicode.o unistr.o \ -ures.o ustring.o rbread.o rbdata.o ubidi.o ubidiln.o \ +uresbund.o uresdata.o ustring.o rbread.o rbdata.o ubidi.o ubidiln.o \ bidi.o uvector.o udata.o unames.o utf_impl.o \ ucnv2022.o ucnvlat1.o ucnv_utf.o ucnvsbcs.o ucnvmbcs.o ucnv_lmb.o +##ures.o ustring.o rbread.o rbdata.o ubidi.o ubidiln.o \ + DEPS = $(OBJECTS:.o=.d) ## Header files to install diff --git a/icu4c/source/common/common.dsp b/icu4c/source/common/common.dsp index d645359a124..02b7b87cbd8 100644 --- a/icu4c/source/common/common.dsp +++ b/icu4c/source/common/common.dsp @@ -81,6 +81,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib advapi32.lib shell32.lib /nologo /base:"0x4a800000" /dll /debug /machine:I386 /out:"..\..\bin\Debug/icuuc.dll" /pdbtype:sept +# SUBTRACT LINK32 /profile !ENDIF @@ -360,7 +361,17 @@ SOURCE=.\ucnvsbcs.c # Begin Source File SOURCE=.\udata.c + +!IF "$(CFG)" == "common - Win32 Release" + # ADD CPP /Ze + +!ELSEIF "$(CFG)" == "common - Win32 Debug" + +# ADD CPP /Ze + +!ENDIF + # End Source File # Begin Source File @@ -411,16 +422,7 @@ SOURCE=.\unistr.cpp # End Source File # Begin Source File -SOURCE=.\ures.cpp - -!IF "$(CFG)" == "common - Win32 Release" - -!ELSEIF "$(CFG)" == "common - Win32 Debug" - -# ADD CPP /Ze - -!ENDIF - +SOURCE=.\uresbund.c # End Source File # Begin Source File @@ -1192,6 +1194,10 @@ SOURCE=.\uresdata.h # End Source File # Begin Source File +SOURCE=.\uresimp.h +# End Source File +# Begin Source File + SOURCE=.\unicode\ustring.h !IF "$(CFG)" == "common - Win32 Release" diff --git a/icu4c/source/common/locid.cpp b/icu4c/source/common/locid.cpp index fb1d6c88873..edf415b6b6d 100644 --- a/icu4c/source/common/locid.cpp +++ b/icu4c/source/common/locid.cpp @@ -34,6 +34,7 @@ #include "unicode/locid.h" #include "unicode/uloc.h" #include "unicode/resbund.h" +#include "uresimp.h" #include "mutex.h" #include "unicode/unicode.h" #include "cmemory.h" @@ -677,15 +678,27 @@ const Locale* Locale::getAvailableLocales(int32_t& count) { // for now, there is a hardcoded list, so just walk through that list and set it up. - if (localeList == 0) - { - count = uloc_countAvailable(); - - Locale *newLocaleList = new Locale[count]; - - for(int32_t i = 0; i < count; i++) - newLocaleList[i].setFromPOSIXID(uloc_getAvailable(i)); - + if (localeList == 0) { + UErrorCode status = U_ZERO_ERROR; + ResourceBundle index(UnicodeString(""), Locale(kIndexLocaleName), status); + ResourceBundle locales = index.get(kIndexTag, status); + + char name[96]; + locales.resetIterator(); + + count = locales.getSize(); + + Locale *newLocaleList = new Locale[count]; + + int32_t i = 0; + UnicodeString temp; + while(locales.hasNext()) { + temp = locales.getNextString(status); + temp.extract(0, temp.length(), name); + name[temp.length()] = '\0'; + newLocaleList[i++].setFromPOSIXID(name); + } + Mutex mutex; if(localeList != 0) { delete []newLocaleList; diff --git a/icu4c/source/common/putil.c b/icu4c/source/common/putil.c index ce82e9b70c8..604c6e8fd8f 100644 --- a/icu4c/source/common/putil.c +++ b/icu4c/source/common/putil.c @@ -1038,7 +1038,11 @@ findLibraryPath(char *path, int size) { } /* define a path for fallbacks */ +#ifdef WIN32 +#define FALLBACK_PATH U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" +#else #define FALLBACK_PATH U_FILE_SEP_STRING "share" U_FILE_SEP_STRING "icu" U_FILE_SEP_STRING U_ICU_VERSION U_FILE_SEP_STRING +#endif /* #include */ /* #include */ @@ -1645,7 +1649,8 @@ _uErrorName[U_ERROR_LIMIT]={ "U_INVALID_TABLE_FORMAT", "U_INVALID_TABLE_FILE", "U_BUFFER_OVERFLOW_ERROR", - "U_UNSUPPORTED_ERROR" + "U_UNSUPPORTED_ERROR", + "U_RESOURCE_TYPE_MISMATCH" }; U_CAPI const char * U_EXPORT2 diff --git a/icu4c/source/common/rbdata.h b/icu4c/source/common/rbdata.h index 0cc0f83b6c0..640e9649d42 100644 --- a/icu4c/source/common/rbdata.h +++ b/icu4c/source/common/rbdata.h @@ -33,6 +33,7 @@ class ResourceBundleData public: virtual ~ResourceBundleData() {} virtual UClassID getDynamicClassID(void) const = 0; + UErrorCode fCreationStatus; }; /** Concrete data class representing a list of strings. */ diff --git a/icu4c/source/common/resbund.cpp b/icu4c/source/common/resbund.cpp index a184c03848d..6337574e7d3 100644 --- a/icu4c/source/common/resbund.cpp +++ b/icu4c/source/common/resbund.cpp @@ -42,24 +42,22 @@ * 06/14/99 stephen Removed methods taking a filename suffix. * 06/22/99 stephen Added missing T_FileStream_close in parse() * 11/09/99 weiv Added getLocale(), rewritten constructForLocale() +* March 2000 weiv complete overhaul. ******************************************************************************* */ -#include "unicode/utypes.h" #include "unicode/resbund.h" - -#include "rbcache.h" #include "mutex.h" +#include "rbdata.h" #include "unistrm.h" #include "filestrm.h" #include "cstring.h" #include "uhash.h" - -#include "rbdata.h" -#include "rbread.h" +#include "uresimp.h" #include +#include #include "cmemory.h" @@ -179,104 +177,24 @@ const char* ResourceBundle::kDefaultSuffix = ".res"; const int32_t ResourceBundle::kDefaultSuffixLen = 4; -const char* ResourceBundle::kDefaultFilename = "default"; -const char* ResourceBundle::kDefaultLocaleName = "default"; -const char* ResourceBundle::kIndexLocaleName = "index"; -const char* ResourceBundle::kIndexFilename = "index"; -const char* ResourceBundle::kIndexTag = "InstalledLocales"; +const char* ResourceBundle::kDefaultFilename = "root"; +const char* ResourceBundle::kDefaultLocaleName = "root"; -// The default minor version and the version separator must be exactly one -// character long. -const char* ResourceBundle::kDefaultMinorVersion = "0"; -const char* ResourceBundle::kVersionSeparator = "."; -const char* ResourceBundle::kVersionTag = "Version"; -ResourceBundleCache* ResourceBundle::fgUserCache = new ResourceBundleCache(); -VisitedFileCache* ResourceBundle::fgUserVisitedFiles = new VisitedFileCache(); -// allocated on the heap so we don't have to expose the definitions of -// these classes to the world - -//----------------------------------------------------------------------------- - -ResourceBundle::LocaleFallbackIterator::LocaleFallbackIterator(const UnicodeString& startingLocale, - const UnicodeString& root, - bool_t useDefaultLocale) -: fLocale(startingLocale), - fRoot(root), - fUseDefaultLocale(useDefaultLocale), - - // Init from the default locale, if asked for. - fDefaultLocale( (useDefaultLocale)? (Locale::getDefault().getName()) : 0, ""), - - fTriedDefaultLocale(FALSE), - fTriedRoot(FALSE) -{ -} - -bool_t -ResourceBundle::LocaleFallbackIterator::nextLocale(UErrorCode& status) -{ - if(fUseDefaultLocale) - fTriedDefaultLocale = fTriedDefaultLocale || (fLocale == fDefaultLocale); - - chopLocale(); - if(status != U_USING_DEFAULT_ERROR) - status = U_USING_FALLBACK_ERROR; - - if(fLocale.length() == 0) { - if(fUseDefaultLocale && !fTriedDefaultLocale) { - fLocale = fDefaultLocale; - fTriedDefaultLocale = TRUE; - status = U_USING_DEFAULT_ERROR; - } - else if( ! fTriedRoot) { - fLocale = fRoot; - fTriedRoot = TRUE; - status = U_USING_DEFAULT_ERROR; - } - else { - status = U_MISSING_RESOURCE_ERROR; - return FALSE; - } - } - - // cerr << "* " << fLocale << " " << u_errorName(status) << endl; - return TRUE; -} - -void -ResourceBundle::LocaleFallbackIterator::chopLocale() -{ - int32_t size = fLocale.length(); - int32_t i; - - for(i = size - 1; i > 0; i--) - if(fLocale[i] == 0x005F/*'_'*/) - break; - - if(i < 0) - i = 0; - - fLocale.remove(i, size - i); -} //----------------------------------------------------------------------------- ResourceBundle::ResourceBundle( const UnicodeString& path, const Locale& locale, UErrorCode& error) - : fgCache(fgUserCache), - fgVisitedFiles(fgUserVisitedFiles) { - constructForLocale(PathInfo(path, kDefaultSuffix), locale, error); + constructForLocale(path, locale, error); } ResourceBundle::ResourceBundle( const UnicodeString& path, UErrorCode& error) - : fgCache(fgUserCache), - fgVisitedFiles(fgUserVisitedFiles) { - constructForLocale(PathInfo(path, kDefaultSuffix), + constructForLocale(path, Locale::getDefault(), error); } @@ -289,371 +207,240 @@ ResourceBundle::ResourceBundle( const UnicodeString& path, ResourceBundle::ResourceBundle( const UnicodeString& path, const char *localeName, UErrorCode& status) - : fgCache(fgUserCache), - fgVisitedFiles(fgUserVisitedFiles), - fPath(path, UnicodeString(kDefaultSuffix,"")), - fIsDataOwned(TRUE), - fRealLocale(localeName), - fVersionID(0) + : fRealLocale(localeName) { - status = U_ZERO_ERROR; - - int32_t i; - for(i = 0; i < kDataCount; ++i) { - fData[i] = 0; - fLoaded[i] = FALSE; - fDataStatus[i] = U_INTERNAL_PROGRAM_ERROR; - } - - fLocaleIterator = 0; - - // If the file doesn't exist, return an error - if(fPath.fileExists(UnicodeString(localeName,""))) { - parse(fPath, UnicodeString(localeName, ""), saveCollationHashtable, - (void*)this, fgCache, status); - } - else { - status = U_MISSING_RESOURCE_ERROR; - } - - // Prevent further attempts to load hashtables - for(i = 0; i < kDataCount; ++i) - fLoaded[i] = TRUE; -} + fItemCache = 0; + int32_t patlen = path.length(); -void -ResourceBundle::saveCollationHashtable(const UnicodeString&, - UHashtable* hashtable, - void* context, - ResourceBundleCache*) -{ - ResourceBundle* bundle = (ResourceBundle*)context; - for(int32_t i = 0; i < kDataCount; ++i) { - if( ! bundle->fLoaded[i]) { - bundle->fData[i] = hashtable; - bundle->fLoaded[i] = TRUE; - bundle->fDataStatus[i] = U_ZERO_ERROR; /* ??? */ - return; +// char name[128]; +// u_UCharsToChars(localeName.getUChars(), name, localeName.length()+1); + if(patlen > 0) { + char pathName[128]; + //u_UCharsToChars(path.getUChars(), pathName, path.length()+1); + path.extract(0, patlen, pathName, ""); + pathName[patlen] = '\0'; + resource = ures_openNoFallback(pathName, localeName, &status); + //ures_openNoFallback(&resource, pathName, name, &status); + } else { + //ures_openNoFallback(&resource, 0, name, &status); + resource = ures_openNoFallback(0, localeName, &status); + } + + if(U_SUCCESS(status)) { + fRealLocale = Locale(localeName); } - } - // Out of room; discard extra data. We only expect to see one anyway. - uhash_close(hashtable); } ResourceBundle::ResourceBundle(const wchar_t* path, const Locale& locale, UErrorCode& err) - : fgCache(fgUserCache), - fgVisitedFiles(fgUserVisitedFiles) { - int32_t wideNameLen = uprv_mbstowcs(NULL, kDefaultSuffix, kDefaultSuffixLen); - wchar_t* wideName = new wchar_t[wideNameLen + 1]; - uprv_mbstowcs(wideName, kDefaultSuffix, kDefaultSuffixLen); - wideName[wideNameLen] = 0; - constructForLocale(PathInfo(path, wideName), locale, err); - delete [] wideName; + constructForLocale(path, locale, err); +} + +ResourceBundle::ResourceBundle(const ResourceBundle &original) { + UErrorCode status = U_ZERO_ERROR; + constructForLocale(ures_getPath(original.resource), Locale(ures_getName(original.resource)), status); +} + +ResourceBundle::ResourceBundle(UResourceBundle *res) { + resource = 0; + fItemCache = 0; + resource = copyResb(0, res); +} + +ResourceBundle& ResourceBundle::operator=(const ResourceBundle& other) +{ + if(this == &other) { + return *this; + } + + if(fItemCache != 0) { + uhash_close(fItemCache); + fItemCache = 0; + } + if(resource != 0) { + ures_close(resource); + resource = 0; + } + UErrorCode status = U_ZERO_ERROR; + if(other.resource->fData != 0) { + constructForLocale(ures_getPath(other.resource), Locale(ures_getName(other.resource)), status); + } else { + resource = copyResb(resource, other.resource); + } + return *this; } ResourceBundle::~ResourceBundle() { - delete fLocaleIterator; - delete [] fVersionID; - - if(fIsDataOwned) - for(int32_t i = 0; i < kDataCount; ++i) { - if(fData[i]) - uhash_close((UHashtable*)fData[i]); + if(fItemCache != 0) { + uhash_close(fItemCache); + } + if(resource != 0) { + ures_close(resource); + } +} + +void +ResourceBundle::deleteValue(void *value) { + delete (ResourceBundleData *)value; +} + +void ResourceBundle::initItemCache(UErrorCode& error) { + if(fItemCache == 0) { + fItemCache = uhash_open(uhash_hashChars, uhash_compareChars, &error); + uhash_setValueDeleter(fItemCache, deleteValue); } } void -ResourceBundle::constructForLocale(const PathInfo& path, +ResourceBundle::constructForLocale(const UnicodeString& path, const Locale& locale, UErrorCode& error) { - int32_t i; - fPath = path; - fIsDataOwned = FALSE; - fVersionID = 0; + char name[128]; + fItemCache = 0; + int32_t patlen = path.length(); - // fRealLocale can be inited in three ways, see 1), 2), 3) - UnicodeString returnedLocale(locale.getName(), ""); - if (returnedLocale.length()!=0) { - // 1) Desired Locale has a name - fRealLocale = locale; - } else { - // 2) Desired Locale name is empty, so we use default locale for the system - fRealLocale = Locale(kDefaultLocaleName); - } - error = U_ZERO_ERROR; - for(i = 1; i < kDataCount; ++i) { - fData[i] = 0; - fDataStatus[i] = U_INTERNAL_PROGRAM_ERROR; - fLoaded[i] = FALSE; - } - - error = U_ZERO_ERROR; - fData[0] = getHashtableForLocale(fRealLocale.getName(), returnedLocale, error); - fLoaded[0] = TRUE; - fDataStatus[0] = U_ZERO_ERROR; - if(U_SUCCESS(error)) - // 3) We're unable to get the desired Locale, so we're using what is provided (fallback occured) - { - /* To avoid calling deprecated api's */ - char *ch; - ch = new char[returnedLocale.size() + 1]; - ch[returnedLocale.extract(0, 0x7fffffff, ch, "")] = 0; - fRealLocale = Locale(ch); - delete [] ch; + if(patlen > 0) { + //u_UCharsToChars(path.getUChars(), name, path.length()+1); + path.extract(0, patlen, name, ""); + name[patlen] = '\0'; + //resource = ures_openFillIn(&resource, name, locale.getName(), &error); + resource = ures_open(name, locale.getName(), &error); + } else { + //resource = ures_openFillIn(&resource, 0, locale.getName(), &error); + resource = ures_open(0, locale.getName(), &error); + } + if(U_SUCCESS(error)) { + fRealLocale = Locale(ures_getRealLocale(resource, &error)); } - - fLocaleIterator = new LocaleFallbackIterator(fRealLocale.getName(), - kDefaultLocaleName, FALSE); } -/** - * Return the hash table with data for the given locale. This method employs - * fallback both in files and in locale names. It returns the locale name - * which is actually used to return the data, if any. - * - * Parse all files found at the given path for the given path, in an effort - * to find data for the given locale. Use fallbacks and defaults as needed. - * Store read in file data in the cache for future use. Return the hashtable - * for the given locale, if found, or 0 if not. - */ -const UHashtable* -ResourceBundle::getHashtableForLocale(const UnicodeString& desiredLocale, - UnicodeString& returnedLocale, - UErrorCode& error) +void +ResourceBundle::constructForLocale(const wchar_t* path, + const Locale& locale, + UErrorCode& error) { - if(U_FAILURE(error)) return NULL; + fItemCache = 0; - error = U_ZERO_ERROR; - const UHashtable* h = getFromCache(fPath, desiredLocale, fgCache); - if(h != 0) { - returnedLocale = desiredLocale; - return h; - } - - LocaleFallbackIterator iterator(desiredLocale, kDefaultFilename, TRUE); - bool_t didTryCacheWithFallback = FALSE; - - // A note on fileError. We are tracking two different error states - // here. One is that returned while iterating over different files. - // For instance, when going from de_CH.txt to de.txt we will get a - // U_USING_FALLBACK_ERROR, but we don't care -- because if de.txt - // contains the de_CH locale, it isn't a fallback, from our - // perspective. Therefore we keep file associated errors in - // fileError, apart from the error parameter. - UErrorCode fileError = U_ZERO_ERROR; + if(path != 0) { + resource = ures_openW(path, locale.getName(), &error); + } else { + resource = ures_open(0, locale.getName(), &error); + } - for(;;) { - // Build a filename for the locale. - if(parseIfUnparsed(fPath, iterator.getLocale(), - fgCache, fgVisitedFiles, error)) { - if(U_FAILURE(error)) - return NULL; - - error = U_ZERO_ERROR; - h = getFromCacheWithFallback(fPath, desiredLocale, - returnedLocale, fgCache, error); - didTryCacheWithFallback = TRUE; - if(h != 0 && U_SUCCESS(error)) - return h; + if(U_SUCCESS(error)) { + fRealLocale = Locale(ures_getRealLocale(resource, &error)); } - - if(!iterator.nextLocale(fileError)) { - error = U_MISSING_RESOURCE_ERROR; - break; - } - } - - // We want to try loading from the cache will fallback at least - // once. These lines of code handle the case in which all of the - // fallback FILES have been loaded, so fgVisitedFiles keeps us from - // parsing them again. In this case we still want to make an - // attempt to load our locale from the cache. - if(didTryCacheWithFallback) - return NULL; - error = U_ZERO_ERROR; - return getFromCacheWithFallback(fPath, desiredLocale, - returnedLocale, fgCache, error); } -/** - * Return the hash table with data for the given locale. This method employs - * fallback in file names only. If data is returned, it will be exactly for - * the given locale. - */ -const UHashtable* -ResourceBundle::getHashtableForLocale(const UnicodeString& desiredLocale, - UErrorCode& error) +UnicodeString ResourceBundle::getString(UErrorCode& status) const { + int32_t len = 0; + const UChar *r = ures_getString(resource, &len, &status); + return UnicodeString(TRUE, r, len); +} + +const char *ResourceBundle::getKey(void) { + return ures_getKey(resource); +} + +UResType ResourceBundle::getType(void) { + return ures_getType(resource); +} + +int32_t ResourceBundle::getSize(void) const { + return ures_getSize(resource); +} + +bool_t ResourceBundle::hasNext(void) const { + return ures_hasNext(resource); +} + +void ResourceBundle::resetIterator(void) { + ures_resetIterator(resource); +} + +ResourceBundle ResourceBundle::getNext(UErrorCode& status) { + return ResourceBundle(ures_getNextResource(resource, 0, &status)); +} + +UnicodeString ResourceBundle::getNextString(UErrorCode& status) { + int32_t len = 0; + const UChar* r = ures_getNextString(resource, &len, 0, &status); + return UnicodeString(TRUE, r, len); +} + +UnicodeString ResourceBundle::getNextString(const char ** key, UErrorCode& status) { + int32_t len = 0; + const UChar* r = ures_getNextString(resource, &len, key, &status); + return UnicodeString(TRUE, r, len); +} + +ResourceBundle ResourceBundle::get(int32_t indexR, UErrorCode& status) const { + return ResourceBundle(ures_getByIndex(resource, indexR, 0, &status)); +} + +UnicodeString ResourceBundle::getStringEx(int32_t indexS, UErrorCode& status) const { + int32_t len = 0; + const UChar* r = ures_getStringByIndex(resource, indexS, &len, &status); + return UnicodeString(TRUE, r, len); +} + +ResourceBundle ResourceBundle::get(const char* key, UErrorCode& status) const { + return ResourceBundle(ures_getByKey(resource, key, 0, &status)); +} + +UnicodeString ResourceBundle::getStringEx(const char* key, UErrorCode& status) const { + int32_t len = 0; + const UChar* r = ures_getStringByKey(resource, key, &len, &status); + return UnicodeString(TRUE, r, len); +} + +const char* +ResourceBundle::getVersionNumber() const { - if(U_FAILURE(error)) - return NULL; - error = U_ZERO_ERROR; - - // First try the cache - const UHashtable* h = getFromCache(fPath, desiredLocale, fgCache); - if(h != 0) - return h; - - // Now try files - LocaleFallbackIterator iterator(desiredLocale, kDefaultFilename, FALSE); - - for(;;) { - UErrorCode parseError = U_ZERO_ERROR; - if(parseIfUnparsed(fPath, iterator.getLocale(), - fgCache, fgVisitedFiles, parseError)) { - if(U_FAILURE(parseError)) { - error = parseError; - return NULL; - } - - const UHashtable* h = getFromCache(fPath, desiredLocale, fgCache); - if(h != 0) - return h; - } - - if(!iterator.nextLocale(error)) - return NULL; - } + return ures_getVersionNumber(resource); } -/** - * Try to retrieve a locale data hash from the cache, using fallbacks - * if necessary. Ultimately we will try to load the data under - * kDefaultLocaleName. - */ -const UHashtable* -ResourceBundle::getFromCacheWithFallback(const PathInfo& path, - const UnicodeString& desiredLocale, - UnicodeString& returnedLocale, - ResourceBundleCache* fgCache, - UErrorCode& error) +const Locale &ResourceBundle::getLocale(void) const { - if(U_FAILURE(error)) - return NULL; - error = U_ZERO_ERROR; - - LocaleFallbackIterator iterator(desiredLocale, kDefaultLocaleName, TRUE); - - for(;;) { - const UHashtable* h = getFromCache(path, iterator.getLocale(), fgCache); - if(h != 0) { - returnedLocale = iterator.getLocale(); - return h; - } - - if(!iterator.nextLocale(error)) - return NULL; - } -} - -/** - * Parse the given file, if it hasn't been attempted already, and if - * it actually exists. Return true if a parse is attempted. Upon - * return, if the return value is true, the error code may be set as a - * result of a parse failure to a failing value. If the parse was - * successful, additional entries may have been created in the cache. - */ -bool_t -ResourceBundle::parseIfUnparsed(const PathInfo& path, - const UnicodeString& locale, - ResourceBundleCache* fgCache, - VisitedFileCache* fgVisitedFiles, - UErrorCode& error) -{ - UnicodeString key(path.makeCacheKey(locale)); - - if(!fgVisitedFiles->wasVisited(key) && path.fileExists(locale)) { - parse(path, locale, addToCache, (void*)&path, fgCache, error); - { - Mutex lock; - fgVisitedFiles->markAsVisited(key); - } - return TRUE; - } - return FALSE; -} - -/** - * Given a tag, try to retrieve the data for that tag. This method is - * semantically const, but may actually modify this object. All - * public API methods such as getString() rely on getDataForTag() - * ultimately. This method implements inheritance of data between - * locales. - */ -const ResourceBundleData* -ResourceBundle::getDataForTag(const char *tag, - UErrorCode& err) const -{ - err = U_ZERO_ERROR; /* just to make sure there's no fallback/etc left over */ - // Iterate over the kDataCount hashtables which may be associated with this - // bundle. At most we have kDataCount, but we may have as few as one. - for(int32_t i = 0; i < kDataCount; ++i) { - - // First try to load up this hashtable, if it hasn't been loaded yet. - if(!fLoaded[i] && fData[i] == 0) { - ResourceBundle* nonconst = (ResourceBundle*)this; - nonconst->fLoaded[i] = TRUE; - if(fLocaleIterator->nextLocale(err)) { - UErrorCode getHashtableStatus = U_ZERO_ERROR; - - nonconst->fDataStatus[i] = err; - nonconst->fData[i] = - nonconst->getHashtableForLocale(fLocaleIterator->getLocale(), getHashtableStatus); - } - } - - - if(fData[i] != 0) { - UnicodeString t(tag, ""); - const ResourceBundleData* s = - (const ResourceBundleData*)uhash_get(fData[i], &t); - if(s != 0) { - err = fDataStatus[i]; /* restore the error from the original lookup. */ - return s; - } - } - } - -#ifdef _DEBUG - // cerr << "Failed to find tag " << tag << " in " << fPath << fRealLocaleID << fFilenameSuffix << endl; - // cerr << *this; -#endif - err = U_MISSING_RESOURCE_ERROR; - return NULL; -} - -void -ResourceBundle::getString( const char *resourceTag, - UnicodeString& theString, - UErrorCode& err) const -{ - if(U_FAILURE(err)) - return; - - const UnicodeString* temp = getString(resourceTag, err); - if(U_SUCCESS(err)) - theString = *temp; + return fRealLocale; } +// Start deprecated API const UnicodeString* ResourceBundle::getString( const char *resourceTag, UErrorCode& err) const { - if(U_FAILURE(err)) - return NULL; - - const ResourceBundleData* data = getDataForTag(resourceTag, err); - if(data != 0 - && data->getDynamicClassID() == StringList::getStaticClassID() - && ((StringList*)data)->fCount == 1) { - return &(((StringList*)data)->fStrings[0]); - } - else err = U_MISSING_RESOURCE_ERROR; - return NULL; + StringList *sldata; + + + if(U_FAILURE(err)) { + return 0; + } + + ((ResourceBundle &)(*this)).initItemCache(err); // Semantically const + + sldata = (StringList *)uhash_get(fItemCache, resourceTag); + + if(sldata == 0) { + const UChar *result = ures_get(resource, resourceTag, &err); + if(result != 0) { + UnicodeString *t = new UnicodeString[1]; + t->setTo(TRUE, result, -1); + sldata = new StringList(t, 1); + } else { + err = U_MISSING_RESOURCE_ERROR; + return 0; + } + sldata->fCreationStatus = err; + uhash_put(fItemCache, (void *)resourceTag, sldata, &err); + } else { + err = sldata->fCreationStatus; + } + return sldata->fStrings; } const UnicodeString* @@ -661,54 +448,60 @@ ResourceBundle::getStringArray( const char *resourceTag, int32_t& count, UErrorCode& err) const { - if(U_FAILURE(err)) - return NULL; - - const ResourceBundleData* data = getDataForTag(resourceTag, err); - if(data != 0 - && data->getDynamicClassID() == StringList::getStaticClassID()) { - count = ((StringList*)data)->fCount; - return ((StringList*)data)->fStrings; - } - err = U_MISSING_RESOURCE_ERROR; - return NULL; -} + UnicodeString *result; + StringList *sldata; + int32_t len=0; -void -ResourceBundle::getArrayItem( const char *resourceTag, - int32_t index, - UnicodeString& theArrayItem, - UErrorCode& err) const -{ - if(U_FAILURE(err)) - return; + if(U_FAILURE(err)) { + return 0; + } - const UnicodeString* temp = getArrayItem(resourceTag, index, err); - if(U_SUCCESS(err)) - theArrayItem = *temp; + ((ResourceBundle &)(*this)).initItemCache(err); // Semantically const + + sldata = (StringList *)uhash_get(fItemCache, resourceTag); + + if(sldata == 0) { + UResourceBundle array; + UErrorCode fallbackInfo = U_ZERO_ERROR; + ures_getByKey(resource, resourceTag, &array, &fallbackInfo); + if(U_SUCCESS(fallbackInfo)) { + count = ures_getSize(&array); + result = new UnicodeString[count]; + const UChar *string = 0; + for(int32_t i=0; isetTo(TRUE, string, len); + } + ures_close(&array); + sldata = new StringList(result, count); + } else { + err = U_MISSING_RESOURCE_ERROR; + return 0; + } + sldata->fCreationStatus = fallbackInfo; + uhash_put(fItemCache, (void *)resourceTag, sldata, &err); + err = fallbackInfo; + } else { + count = sldata->fCount; + err = sldata->fCreationStatus; + } + return sldata->fStrings; } const UnicodeString* ResourceBundle::getArrayItem( const char *resourceTag, - int32_t index, + int32_t indexS, UErrorCode& err) const { - if(U_FAILURE(err)) - return NULL; + int32_t num; + const UnicodeString *array = getStringArray(resourceTag, num, err); - // Casting to unsigned turns a signed value into a large unsigned - // value. This allows us to do one comparison to check that 0 <= - // index < count, instead of two separate comparisons for each index - // check. - const ResourceBundleData* data = getDataForTag(resourceTag, err); - if(data != 0 - && data->getDynamicClassID() == StringList::getStaticClassID() - && (uint32_t)index < (uint32_t)((StringList*)data)->fCount) { - return &(((StringList*)data)->fStrings[index]); - } - else - err = U_MISSING_RESOURCE_ERROR; - return NULL; + if(U_FAILURE(err) || indexS<0 || indexS>=num) { + err = U_MISSING_RESOURCE_ERROR; + return 0; + } else { + return &array[indexS]; + } } const UnicodeString** @@ -717,22 +510,168 @@ ResourceBundle::get2dArray(const char *resourceTag, int32_t& columnCount, UErrorCode& err) const { - if(U_FAILURE(err)) - return NULL; + UnicodeString **result = 0; + String2dList *sldata = 0; + int32_t len=0; - const ResourceBundleData* data = getDataForTag(resourceTag, err); - if(data != 0 - && data->getDynamicClassID() == String2dList::getStaticClassID()) { - String2dList *list = (String2dList*)data; - rowCount = list->fRowCount; - columnCount = list->fColCount; - // Why is this cast required? It shouldn't be. [LIU] - return (const UnicodeString**)list->fStrings; - } - err = U_MISSING_RESOURCE_ERROR; - return NULL; + if(U_FAILURE(err)) { + return 0; + } + + ((ResourceBundle &)(*this)).initItemCache(err); // Semantically const + + sldata = (String2dList *)uhash_get(fItemCache, resourceTag); + + if(sldata == 0) { + UResourceBundle array; + UErrorCode fallbackInfo = U_ZERO_ERROR; + ures_getByKey(resource, resourceTag, &array, &fallbackInfo); + if(U_SUCCESS(fallbackInfo)) { + rowCount = ures_getSize(&array); + if(rowCount > 0) { + result = new UnicodeString*[rowCount]; + UResourceBundle row; + ures_getByIndex(&array, 0, &row, &err); + columnCount = ures_getSize(&row); + const UChar* string = 0; + for(int32_t i=0; isetTo(TRUE, string, len); + } + ures_close(&row); + } + sldata = new String2dList(result, rowCount, columnCount); + sldata->fCreationStatus = fallbackInfo; + uhash_put(fItemCache, (void *)resourceTag, sldata, &err); + err = fallbackInfo; + } + ures_close(&array); + } else { + err = U_MISSING_RESOURCE_ERROR; + return 0; + } + } else { + rowCount = sldata->fRowCount; + columnCount = sldata->fColCount; + err = sldata->fCreationStatus; + } + + return (const UnicodeString**)sldata->fStrings; } + +const UnicodeString* +ResourceBundle::get2dArrayItem(const char *resourceTag, + int32_t rowIndex, + int32_t columnIndex, + UErrorCode& err) const +{ + int32_t rows = 0; + int32_t columns = 0; + + const UnicodeString** array= get2dArray(resourceTag, rows, columns, err); + + if(array == 0 || rowIndex < 0 || columnIndex < 0 || rowIndex >= rows || columnIndex >= columns) { + err = U_MISSING_RESOURCE_ERROR; + return 0; + } else { + return &array[rowIndex][columnIndex]; + } +} + +const UnicodeString* +ResourceBundle::getTaggedArrayItem( const char *resourceTag, + const UnicodeString& itemTag, + UErrorCode& err) const +{ + StringList *sldata = 0; + int32_t len = 0; + + if(U_FAILURE(err)) { + return 0; + } + + char item[256]; + char key[256]; + int32_t taglen = itemTag.length(); + //u_UCharsToChars(itemTag.getUChars(), key, itemTag.length()+1); + //u_UCharsToChars(itemTag.getUChars(), item, itemTag.length()+1); + itemTag.extract(0, taglen, key, ""); + key[taglen] = '\0'; + itemTag.extract(0, taglen, item, ""); + item[taglen] = '\0'; + uprv_strcat(key, resourceTag); + + ((ResourceBundle &)(*this)).initItemCache(err); // Semantically const + + sldata = (StringList *)uhash_get(fItemCache, key); + + if(sldata == 0) { + UResourceBundle table; + UErrorCode fallbackInfo = U_ZERO_ERROR; + ures_getByKey(resource, resourceTag, &table, &fallbackInfo); + if(U_SUCCESS(fallbackInfo)) { + const UChar *result = ures_getStringByKey(&table, item, &len, &err); + if(result != 0) { + UnicodeString *t = new UnicodeString[1]; + t->setTo(TRUE, result, len); + sldata = new StringList(t, 1); + } else { + err = U_MISSING_RESOURCE_ERROR; + return 0; + } + ures_close(&table); + sldata->fCreationStatus = fallbackInfo; + uhash_put(fItemCache, key, sldata, &err); + err = fallbackInfo; + } else { + err = U_MISSING_RESOURCE_ERROR; + return 0; + } + } else { + err = sldata->fCreationStatus; + } + return sldata->fStrings; +} + +void +ResourceBundle::getTaggedArray( const char *resourceTag, + UnicodeString*& itemTags, + UnicodeString*& items, + int32_t& numItems, + UErrorCode& err) const +{ + if(U_FAILURE(err)) { + return; + } + UResourceBundle table; + ures_getByKey(resource, resourceTag, &table, &err); + if(U_SUCCESS(err)) { + numItems = ures_getSize(&table); + itemTags = new UnicodeString[numItems]; + items = new UnicodeString[numItems]; + const UChar *value = 0; + const char *key = 0; + int32_t len = 0; + int16_t indexR = -1; + res_getNextStringTableItem(&(table.fResData), table.fRes, &value, &key, &len, &indexR); + while(value != 0) { + items[indexR-1].setTo(value); + itemTags[indexR-1].setTo(key); + res_getNextStringTableItem(&(table.fResData), table.fRes, &value, &key, &len, &indexR); + } + } else { + err = U_MISSING_RESOURCE_ERROR; + return; + } +} + +// start removed API + +/* void ResourceBundle::get2dArrayItem(const char *resourceTag, int32_t rowIndex, @@ -749,33 +688,9 @@ ResourceBundle::get2dArrayItem(const char *resourceTag, if(U_SUCCESS(err)) theArrayItem = *temp; } +*/ -const UnicodeString* -ResourceBundle::get2dArrayItem(const char *resourceTag, - int32_t rowIndex, - int32_t columnIndex, - UErrorCode& err) const -{ - if(U_FAILURE(err)) - return NULL; - - const ResourceBundleData* data = getDataForTag(resourceTag, err); - if(data != 0 - && data->getDynamicClassID() == String2dList::getStaticClassID()) { - String2dList *list = (String2dList*)data; - // Casting to unsigned turns a signed value into a large unsigned - // value. This allows us to do one comparison to check that 0 <= - // index < count, instead of two separate comparisons for each - // index check. - if(((uint32_t)rowIndex) < (uint32_t)(list->fRowCount) - && ((uint32_t)columnIndex) < (uint32_t)(list->fColCount)) { - return &(list->fStrings[rowIndex][columnIndex]); - } - } - err = U_MISSING_RESOURCE_ERROR; - return NULL; -} - +/* void ResourceBundle::getTaggedArrayItem( const char *resourceTag, const UnicodeString& itemTag, @@ -790,561 +705,39 @@ ResourceBundle::getTaggedArrayItem( const char *resourceTag, if(U_SUCCESS(err)) theArrayItem = *temp; } +*/ -const UnicodeString* -ResourceBundle::getTaggedArrayItem( const char *resourceTag, - const UnicodeString& itemTag, - UErrorCode& err) const -{ - if(U_FAILURE(err)) - return NULL; - - const ResourceBundleData* data = getDataForTag(resourceTag, err); - if(data != 0 - && data->getDynamicClassID() == TaggedList::getStaticClassID()) { - const UnicodeString* s = ((TaggedList*)data)->get(itemTag); - if(s != 0) - return s; - } - - err = U_MISSING_RESOURCE_ERROR; - return NULL; -} - -extern "C" void -T_ResourceBundle_getTaggedArrayUChars(const ResourceBundle* bundle, - const char *resourceTag, - UChar const** itemTags, - UChar const** items, - int32_t maxItems, - int32_t* numItems, - UErrorCode* err) -{ - // this function is here solely because there seems to be no way to - // declare an extern "C" function as a friend of a class. So we - // have a function with ordinary C++ linkage that is a friend of - // ResourceBundle and does the work, and a hidden method with C - // linkage that calls it and is used by the C wrappers. Disgusting, - // isn't it? This was all rtg's idea. --jf 12/16/98 - getTaggedArrayUCharsImplementation(bundle, resourceTag, - itemTags, items, maxItems, - *numItems, *err); -} - -void -getTaggedArrayUCharsImplementation( const ResourceBundle* bundle, - const char *resourceTag, - UChar const** itemTags, - UChar const** items, - int32_t maxItems, - int32_t& numItems, - UErrorCode& err) -{ - // this is here solely to support the C implementation of - // ResourceBundle. This function isn't defined as part of the API; - // The C wrappers know it's here and define it on their own. --jf - // 12/16/98 - if(U_FAILURE(err)) - return; - - const ResourceBundleData* data = bundle->getDataForTag(resourceTag, err); - if(U_FAILURE(err) || data == 0 - || data->getDynamicClassID() != TaggedList::getStaticClassID()) { - err = U_MISSING_RESOURCE_ERROR; - return; - } - - numItems = 0; - int32_t pos = -1; - const UnicodeString *key, *value; - while (((TaggedList*)data)->nextElement(key, value, pos) && - numItems < maxItems) { - itemTags[numItems] = key->getUChars(); - items[numItems] = value->getUChars(); - numItems++; - } -} - +/* void -ResourceBundle::getTaggedArray( const char *resourceTag, - UnicodeString*& itemTags, - UnicodeString*& items, - int32_t& numItems, +ResourceBundle::getArrayItem( const char *resourceTag, + int32_t index, + UnicodeString& theArrayItem, UErrorCode& err) const { if(U_FAILURE(err)) return; - const ResourceBundleData* data = getDataForTag(resourceTag, err); - if(U_FAILURE(err) || data == 0 - || data->getDynamicClassID() != TaggedList::getStaticClassID()) { - err = U_MISSING_RESOURCE_ERROR; - return; - } - - // go through the resource once and count how many items there are - - numItems = ((TaggedList*)data)->count(); - - // now create the string arrays and go through the hash table again, this - // time copying the keys and values into the string arrays - itemTags = new UnicodeString[numItems]; - items = new UnicodeString[numItems]; - - numItems = 0; - int32_t pos = -1; - const UnicodeString *key, *value; - while (((TaggedList*)data)->nextElement(key, value, pos)) { - itemTags[numItems] = *key; - items[numItems] = *value; - numItems++; - } + const UnicodeString* temp = getArrayItem(resourceTag, index, err); + if(U_SUCCESS(err)) + theArrayItem = *temp; } - -const char* -ResourceBundle::getVersionNumber() const -{ - if(fVersionID == 0) { - // If the version ID has not been built yet, then do so. Retrieve - // the minor version from the file. - UErrorCode status = U_ZERO_ERROR; - UnicodeString minor_version; - getString(kVersionTag, minor_version, status); - - // Determine the length of of the final version string. This is - // the length of the major part + the length of the separator - // (==1) + the length of the minor part (+ 1 for the zero byte at - // the end). - int32_t len = uprv_strlen(U_ICU_VERSION); - int32_t minor_len = 0; - if(U_SUCCESS(status) && minor_version.length() > 0) - minor_len = minor_version.length(); - len += (minor_len > 0) ? minor_len : 1 /*==uprv_strlen(kDefaultMinorVersion)*/; - ++len; // Add length of separator - - // Allocate the string, and build it up. - // + 1 for zero byte - ((ResourceBundle*)this)->fVersionID = new char[1 + len]; - - uprv_strcpy(fVersionID, U_ICU_VERSION); - uprv_strcat(fVersionID, kVersionSeparator); - if(minor_len > 0) { - minor_version.extract(0, minor_len, fVersionID + len - minor_len); - fVersionID[len] = 0; - } - else { - uprv_strcat(fVersionID, kDefaultMinorVersion); - } - } - return fVersionID; -} - -const UnicodeString* -ResourceBundle::listInstalledLocales(const UnicodeString& path, - int32_t& numInstalledLocales) -{ - const UnicodeString kDefaultSuffixString = UnicodeString(kDefaultSuffix,""); +*/ - const UHashtable* h = getFromCache(PathInfo(path, kDefaultSuffixString), - UnicodeString(kIndexLocaleName,""), fgUserCache); - - if(h == 0) { - UErrorCode error = U_ZERO_ERROR; - if(parseIfUnparsed(PathInfo(path, kDefaultSuffixString), - UnicodeString(kIndexFilename,""), fgUserCache, - fgUserVisitedFiles, error)) { - h = getFromCache(PathInfo(path, kDefaultSuffixString), - UnicodeString(kIndexLocaleName,""), fgUserCache); - } - } - - if(h != 0) { - UnicodeString ukIndexTag = UnicodeString(kIndexTag,""); - ResourceBundleData *data = - (ResourceBundleData*) uhash_get(h, &ukIndexTag); - if(data != 0 - && data->getDynamicClassID() == StringList::getStaticClassID()) { - numInstalledLocales = ((StringList*)data)->fCount; - return ((StringList*)data)->fStrings; - } - } - - numInstalledLocales = 0; - return NULL; -} - -extern "C" const UnicodeString** -T_ResourceBundle_listInstalledLocales(const char* path, - int32_t* numInstalledLocales) -{ - // this is here solely to support the C implementation of Locale. - // This function isn't defined as part of the API; T_Locale knows - // it's here and defines it on its own. --rtg 11/28/98 - - return listInstalledLocalesImplementation(path, numInstalledLocales); -} - -const UnicodeString** -listInstalledLocalesImplementation(const char* path, - int32_t* numInstalledLocales) -{ - // this function is here solely because there seems to be no way to - // declare an extern "C" function as a friend of a class. So we - // have a function with ordinary C++ linkage that is a friend of - // ResourceBundle and does the work, and a hidden method with C - // linkage that calls it and is used by the C implementation of - // Locale. Disgusting, isn't it? --rtg 11/30/98 - const UnicodeString* array = (ResourceBundle::listInstalledLocales(UnicodeString(path,""), *numInstalledLocales)); - const UnicodeString** arrayOfPtrs = (const UnicodeString**) new UnicodeString*[*numInstalledLocales]; - for(int i = 0; i < *numInstalledLocales; i++) - arrayOfPtrs[i] = &array[i]; - return arrayOfPtrs; -} - -int32_t -T_ResourceBundle_countArrayItemsImplementation(const ResourceBundle* resourceBundle, - const char* resourceKey, - UErrorCode& err) -{ - if(U_FAILURE(err)) - return 0; - - if(!resourceKey) { - err = U_ILLEGAL_ARGUMENT_ERROR; - return 0; - } - const ResourceBundleData* data = resourceBundle->getDataForTag(resourceKey, - err); - if(U_FAILURE(err)) - return 0; - - UClassID rbkeyClassID = data->getDynamicClassID(); - int32_t numItems = 0; - - if(rbkeyClassID == StringList::getStaticClassID()) { - numItems = ((StringList*)data)->fCount; - } - else if(rbkeyClassID == TaggedList::getStaticClassID()) { - numItems = ((TaggedList*)data)->count(); - } - else if(rbkeyClassID == String2dList::getStaticClassID()) { - numItems = ((String2dList*)data)->fRowCount; - } - else { - err = U_MISSING_RESOURCE_ERROR; - return 0; - } - - return numItems; -} - - -extern "C" int32_t -T_ResourceBundle_countArrayItems(const ResourceBundle* resourceBundle, - const char* resourceKey, - UErrorCode* err) -{ - return T_ResourceBundle_countArrayItemsImplementation(resourceBundle, - resourceKey, - *err); -} - -/** - * Retrieve a ResourceBundle from the cache. Return NULL if not found. - */ -const UHashtable* -ResourceBundle::getFromCache(const PathInfo& path, - const UnicodeString& localeName, - ResourceBundleCache* fgCache) -{ - UnicodeString keyname(path.makeHashkey(localeName)); - Mutex lock; - return fgCache->get(keyname); -} - -/** - * Parse a file, storing the resource data in the cache. - */ -void -ResourceBundle::parse(const PathInfo& path, - const UnicodeString& locale, - Handler handler, - void *context, - ResourceBundleCache *fgCache, - UErrorCode& status) -{ - FileStream *f; - UnicodeString localeName, realLocale; - UHashtable *data; - - if (U_FAILURE(status)) return; - - f = path.openFile(locale); - if(f == 0) { - status = U_FILE_ACCESS_ERROR; - return; - } - - realLocale = locale; - /* Get the data from the compiled resource bundle file */ - data = rb_parse(f, localeName, status); - - /* Close the file */ - T_FileStream_close(f); - - if(U_FAILURE(status)) { - return; - } - /* If an alias file is encountered, parse the new locale file. */ - if (data == 0) { - f = path.openFile(localeName); - if(f == 0) { - status = U_FILE_ACCESS_ERROR; - return; - } - data = rb_parse(f, localeName, status); - T_FileStream_close(f); - - if(U_FAILURE(status)) { - return; - } - localeName = realLocale; - } - - /* Invoke the handler function */ - handler(localeName, data, context, fgCache); -} - +/* void -ResourceBundle::addToCache(const UnicodeString& localeName, - UHashtable* hashtable, - void* context, - ResourceBundleCache* fgCache) +ResourceBundle::getString( const char *resourceTag, + UnicodeString& theString, + UErrorCode& err) const { - PathInfo *c = (PathInfo*)context; - UnicodeString keyName(c->makeHashkey(localeName)); - Mutex lock; - if (fgCache->get(keyName) == 0) { - fgCache->put(keyName, hashtable); - } + if(U_FAILURE(err)) + return; + + const UnicodeString* temp = getString(resourceTag, err); + if(U_SUCCESS(err)) + theString = *temp; } +*/ -const Locale &ResourceBundle::getLocale(void) const -{ - return fRealLocale; -} - -ResourceBundle::PathInfo::PathInfo() - : fWPrefix(NULL), fWSuffix(NULL) -{} - -ResourceBundle::PathInfo::PathInfo(const PathInfo& source) - : fPrefix(source.fPrefix), - fSuffix(source.fSuffix), - fWPrefix(NULL), fWSuffix(NULL) -{ - if(source.fWPrefix) { - fWPrefix = new wchar_t[uprv_wcslen(source.fWPrefix)+1]; - fWSuffix = new wchar_t[uprv_wcslen(source.fWSuffix)+1]; - uprv_wcscpy(fWPrefix, source.fWPrefix); - uprv_wcscpy(fWSuffix, source.fWSuffix); - } -} - -ResourceBundle::PathInfo::PathInfo(const UnicodeString& path) - : fPrefix(path), - fWPrefix(NULL), - fWSuffix(NULL) -{} - -ResourceBundle::PathInfo::PathInfo(const UnicodeString& path, - const UnicodeString& suffix) - : fPrefix(path), - fSuffix(suffix), - fWPrefix(NULL), - fWSuffix(NULL) -{} - -ResourceBundle::PathInfo::PathInfo(const wchar_t* path, - const wchar_t* suffix) - : fPrefix(), - fSuffix(), - fWPrefix(NULL), - fWSuffix(NULL) -{ - fWPrefix = new wchar_t[uprv_wcslen(path)+1]; - fWSuffix = new wchar_t[uprv_wcslen(suffix)+1]; - uprv_wcscpy(fWPrefix, path); - uprv_wcscpy(fWSuffix, suffix); -} - -ResourceBundle::PathInfo::~PathInfo() -{ - delete [] fWPrefix; - delete [] fWSuffix; -} - -ResourceBundle::PathInfo& -ResourceBundle::PathInfo::operator=(const PathInfo& source) -{ - if(this != &source) { - wchar_t* tempPref = NULL; - wchar_t* tempSuff = NULL; - if(source.fWPrefix) { - tempPref = new wchar_t[uprv_wcslen(source.fWPrefix)+1]; - tempSuff = new wchar_t[uprv_wcslen(source.fWSuffix)+1]; - uprv_wcscpy(tempPref, source.fWPrefix); - uprv_wcscpy(tempSuff, source.fWSuffix); - } - delete fWPrefix; - fWPrefix = tempPref; - delete fWSuffix; - fWSuffix = tempSuff; - fPrefix = source.fPrefix; - fSuffix = source.fSuffix; - } - return *this; -} - -bool_t -ResourceBundle::PathInfo::fileExists(const UnicodeString& localeName) const -{ - FileStream *temp = openFile(localeName); - if(temp) { - T_FileStream_close(temp); - return TRUE; - } - else { - return FALSE; - } -} - -UnicodeString -ResourceBundle::PathInfo::makeCacheKey(const UnicodeString& name) const -{ - if(fWPrefix) { - UnicodeString key; - - size_t prefSize = uprv_wcstombs(NULL, fWPrefix, ((size_t)-1) >> 1); - size_t suffSize = uprv_wcstombs(NULL, fWSuffix, ((size_t)-1) >> 1); - size_t tempSize = uprv_max((int32_t)prefSize, (int32_t)suffSize); - char *temp = new char[tempSize + 1]; - - tempSize = uprv_wcstombs(temp, fWPrefix, prefSize); - temp[tempSize] = 0; - key += UnicodeString(temp); - - key += name; - - tempSize = uprv_wcstombs(temp, fWSuffix, suffSize); - temp[tempSize] = 0; - key += UnicodeString(temp); - - delete [] temp; - - return key; - } - else { - UnicodeString workingName(fPrefix); - workingName += name; - workingName += fSuffix; - - return workingName; - } -} - -UnicodeString -ResourceBundle::PathInfo::makeHashkey(const UnicodeString& localeName) const -{ - if(fWPrefix) { - UnicodeString key(localeName); - - key += kSeparator; - - size_t prefSize = uprv_wcstombs(NULL, fWPrefix, ((size_t)-1) >> 1); - size_t suffSize = uprv_wcstombs(NULL, fWSuffix, ((size_t)-1) >> 1); - size_t tempSize = uprv_max((int32_t)prefSize, (int32_t)suffSize); - char *temp = new char[tempSize + 1]; - - tempSize = uprv_wcstombs(temp, fWSuffix, suffSize); - temp[tempSize] = 0; - key += UnicodeString(temp); - - key += kSeparator; - - tempSize = uprv_wcstombs(temp, fWPrefix, prefSize); - temp[tempSize] = 0; - key += UnicodeString(temp); - - delete [] temp; - - return key; - } - else { - UnicodeString keyName = localeName; - keyName += kSeparator; - keyName += fSuffix; - keyName += kSeparator; - keyName += fPrefix; - return keyName; - } -} - -FileStream* -ResourceBundle::PathInfo::openFile(const UnicodeString& localeName) const -{ - if(fWPrefix) { - //use the wide version of fopen in TPlatformUtilities. - int32_t nameSize = localeName.length(); - char* temp = new char[nameSize + 1]; - localeName.extract(0, nameSize, temp); - temp[nameSize] = 0; - int32_t wideNameLen = uprv_mbstowcs(NULL, temp, nameSize); - wchar_t* wideName = new wchar_t[wideNameLen + 1]; - uprv_mbstowcs(wideName, temp, nameSize); - wideName[wideNameLen] = 0; - delete [] temp; - - size_t prefLen = uprv_wcslen(fWPrefix); - size_t suffLen = uprv_wcslen(fWSuffix); - - int32_t destSize = prefLen + suffLen + wideNameLen; - wchar_t* dest = new wchar_t[destSize + 1]; - uprv_wcscpy(dest, fWPrefix); - dest[prefLen] = 0; - - uprv_wcscat(dest, wideName); - dest[prefLen + wideNameLen] = 0; - - uprv_wcscat(dest, fWSuffix); - dest[destSize] = 0; - - int32_t fmodeLen = uprv_mbstowcs(NULL, "rb", 2); - wchar_t* fmode = new wchar_t[fmodeLen + 1]; - uprv_mbstowcs(fmode, "rb", 2); - fmode[fmodeLen] = 0; - - FileStream* result = T_FileStream_wopen(dest, fmode); - - delete [] fmode; - delete [] dest; - delete [] wideName; - return result; - } - else { - //open file using standard char* routines - UnicodeString workingName(makeCacheKey(localeName)); - int32_t size = workingName.length(); - char* returnVal = new char[size + 1]; - workingName.extract(0, size, returnVal, ""); - returnVal[size] = 0; - FileStream* result = T_FileStream_open(returnVal, "rb"); - delete [] returnVal; - return result; - } -} - -const UChar ResourceBundle::PathInfo::kSeparator = 0xF8FF; //eof diff --git a/icu4c/source/common/ucnv.c b/icu4c/source/common/ucnv.c index af5c5b81b52..62931a7e1f7 100644 --- a/icu4c/source/common/ucnv.c +++ b/icu4c/source/common/ucnv.c @@ -273,16 +273,14 @@ int32_t ucnv_getDisplayName (const UConverter * converter, /*create an RB, init the fill-in string, gets it from the RB */ rb = ures_open (NULL, displayLocale, err); - stringToWrite = ures_get (rb, + stringToWrite = ures_getStringByKey(rb, converter->sharedData->staticData->name, + &stringToWriteLength, err); - if (rb) ures_close (rb); - if (U_SUCCESS (*err)) - stringToWriteLength = u_strlen (stringToWrite); - else + if(U_FAILURE(*err)) { /*Error While creating or getting resource from the resource bundle *use the internal name instead diff --git a/icu4c/source/common/uloc.c b/icu4c/source/common/uloc.c index 072e26c81af..25d14fa76ee 100644 --- a/icu4c/source/common/uloc.c +++ b/icu4c/source/common/uloc.c @@ -22,7 +22,7 @@ #include "unicode/uloc.h" #include "unicode/utypes.h" -#include "unicode/ures.h" +#include "uresimp.h" #include "unicode/uchar.h" #include "umutex.h" #include "cstring.h" @@ -497,14 +497,15 @@ uint32_t uloc_getLCID(const char* localeID) UErrorCode err = U_ZERO_ERROR; char temp[30]; const UChar* lcid = NULL; + int32_t lcidLen = 0; uint32_t result = 0; - UResourceBundle* bundle = ures_open(u_getDataDirectory(), localeID, &err); + UResourceBundle* bundle = ures_open(NULL, localeID, &err); if (U_SUCCESS(err)) { - lcid = ures_get(bundle, _kLocaleID, &err); + lcid = ures_getStringByKey(bundle, _kLocaleID, &lcidLen, &err); ures_close(bundle); - if (U_FAILURE(err) || !lcid || u_strlen(lcid) == 0) + if (U_FAILURE(err) || !lcid || lcidLen == 0) { return 0; } @@ -530,7 +531,6 @@ int32_t uloc_getDisplayLanguage(const char* locale, UResourceBundle* bundle; const UChar* temp = NULL; bool_t isDefaultLocale = FALSE; - const char* dataDir = u_getDataDirectory(); bool_t done = FALSE; if (U_FAILURE(*status)) return 0; @@ -579,7 +579,7 @@ int32_t uloc_getDisplayLanguage(const char* locale, } - bundle = ures_open(dataDir, inLocale, &err); + bundle = ures_open(NULL, inLocale, &err); if (U_SUCCESS(err)) { @@ -654,7 +654,6 @@ int32_t uloc_getDisplayCountry(const char* locale, UResourceBundle* bundle = NULL; char inLocaleBuffer[TEMPBUFSIZE]; bool_t isDefaultLocale = FALSE; - const char* dataDir = u_getDataDirectory(); bool_t done = FALSE; if (U_FAILURE(*status)) return 0; @@ -703,7 +702,7 @@ int32_t uloc_getDisplayCountry(const char* locale, } - bundle = ures_open(dataDir, inLocale, &err); + bundle = ures_open(NULL, inLocale, &err); if (U_SUCCESS(err)) { @@ -777,7 +776,6 @@ int32_t uloc_getDisplayVariant(const char* locale, bool_t isDefaultLocale = FALSE; char inVariantTagBuffer[TEMPBUFSIZE+2]; char* inVariantTag = inVariantTagBuffer; - const char* dataDir = u_getDataDirectory(); bool_t done = FALSE; if (U_FAILURE(*status)) return 0; @@ -839,7 +837,7 @@ int32_t uloc_getDisplayVariant(const char* locale, } - bundle = ures_open(dataDir, inLocale, &err); + bundle = ures_open(NULL, inLocale, &err); if (U_SUCCESS(err)) { @@ -1006,15 +1004,6 @@ int32_t uloc_getDisplayName(const char* locale, return i; } - -/** - * Returns a list of all available locales. The return value is a pointer to - * an array of pointers to ULocale objects. Both this array and the pointers - * it contains are owned by ICU and should not be deleted or written through - * by the caller. The array is terminated by a null pointer. RTG - */ -U_CAPI UnicodeString** T_ResourceBundle_listInstalledLocales(const char* path, int32_t* numInstalledLocales); - const char* uloc_getAvailable(int32_t offset) { @@ -1035,41 +1024,47 @@ int32_t uloc_countAvailable() void _lazyEvaluate_installedLocales() { - UnicodeString** temp; - char ** temp2; - int i; - int32_t strSize; - if (_installedLocales == NULL) - { - temp = T_ResourceBundle_listInstalledLocales(u_getDataDirectory(), - &_installedLocalesCount); - temp2 = (char **) uprv_malloc(sizeof(char*) * (_installedLocalesCount+1)); - - for (i = 0; i < _installedLocalesCount; i++) - { - strSize = T_UnicodeString_length(temp[i]); - temp2[i] = (char*) uprv_malloc(sizeof(char) * - (strSize + 1)); + UResourceBundle *index = NULL; + UResourceBundle installed; + UErrorCode status = U_ZERO_ERROR; + const UChar *lname; + char ** temp; + int32_t i = 0; + int32_t len = 0; - T_UnicodeString_extract(temp[i], temp2[i]); - temp2[i][strSize] = 0; /* Terminate the string */ - } - { - umtx_lock(NULL); - if (_installedLocales == NULL) - { - _installedLocales = temp2; - temp2 = NULL; + index = ures_open(NULL, kIndexLocaleName, &status); + ures_getByKey(index, kIndexTag, &installed, &status); + + if(U_SUCCESS(status)) { + _installedLocalesCount = ures_getSize(&installed); + temp = (char **) uprv_malloc(sizeof(char*) * (_installedLocalesCount+1)); + + ures_resetIterator(&installed); + while(ures_hasNext(&installed)) { + lname = ures_getNextString(&installed, &len, NULL, &status); + temp[i] = (char*) uprv_malloc(sizeof(char) * (len + 1)); + + u_UCharsToChars(lname, temp[i], len); + temp[i][len] = 0; /* Terminate the string */ + i++; } - else { - for (i = 0; i < _installedLocalesCount; i++) uprv_free(temp2[i]); - uprv_free(temp2); - } - umtx_unlock(NULL); + { + umtx_lock(NULL); + if (_installedLocales == NULL) + { + _installedLocales = temp; + temp = NULL; + } else { + for (i = 0; i < _installedLocalesCount; i++) uprv_free(temp[i]); + uprv_free(temp); + } + umtx_unlock(NULL); } + ures_close(&installed); } + ures_close(index); } /** diff --git a/icu4c/source/common/unicode/resbund.h b/icu4c/source/common/unicode/resbund.h index 3ac7d241e29..912a1d1f726 100644 --- a/icu4c/source/common/unicode/resbund.h +++ b/icu4c/source/common/unicode/resbund.h @@ -46,14 +46,14 @@ #ifndef RESBUND_H #define RESBUND_H +#include "unicode/ures.h" #include "unicode/utypes.h" #include "unicode/unistr.h" #include "unicode/locid.h" +#include "uhash.h" +#include + -class RBHashtable; -class ResourceBundleData; -class ResourceBundleCache; -class VisitedFileCache; #ifndef _FILESTRM typedef struct _FileStream FileStream; #endif @@ -62,21 +62,8 @@ typedef struct _FileStream FileStream; class Locale; class RuleBasedCollator; class ResourceBundle; -extern int32_t T_ResourceBundle_countArrayItemsImplementation( - const ResourceBundle* resourceBundle, - const char* resourceKey, - UErrorCode& err); -extern const UnicodeString** listInstalledLocalesImplementation( - const char* path, - int32_t* numInstalledLocales); -extern void getTaggedArrayUCharsImplementation( - const ResourceBundle* bundle, - const char *resourceTag, - UChar const** itemTags, - UChar const** items, - int32_t maxItems, - int32_t& numItems, - UErrorCode& err); +//struct UHashtable; + /** * A class representing a collection of resource information pertaining to a given @@ -199,23 +186,148 @@ public: ResourceBundle( const wchar_t* path, const Locale& locale, UErrorCode& err); + ResourceBundle(const ResourceBundle &original); + ResourceBundle(UResourceBundle *res); + + ResourceBundle& operator=(const ResourceBundle& other); ~ResourceBundle(); +/** + * Returns the size of a resource. Size for scalar types is always 1, and for vector/table types is + * the number of child resources. + * + * @return number of resources in a given resource. + * @draft + */ + int32_t getSize(void) const; +/** + * returns a string from a string resource type + * + * @param status: fills in the outgoing error code + * could be U_MISSING_RESOURCE_ERROR if the key is not found + * could be a non-failing error + * e.g.: U_USING_FALLBACK_ERROR,U_USING_DEFAULT_ERROR + * @return a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file. + * @draft + */ + UnicodeString getString(UErrorCode& status) const; +/** + * Checks whether the resource has another element to iterate over. + * + * @return TRUE if there are more elements, FALSE if there is no more elements + * @draft + */ + bool_t hasNext(void) const; +/** + * Resets the internal context of a resource so that iteration starts from the first element. + * + * @draft + */ + void resetIterator(void); + +/** + * Returns the key associated with this resource. Not all the resources have a key - only + * those that are members of a table. + * + * @return a key associated to this resource, or NULL if it doesn't have a key + * @draft + */ + const char *getKey(void); + +/** + * Returns the type of a resource. Available types are defined in enum UResType + * + * @return type of the given resource. + * @draft + */ + UResType getType(void); + +/** + * Returns the next resource in a given resource or NULL if there are no more resources + * + * @param status fills in the outgoing error code + * @return ResourceBundle object. + * @draft + */ + ResourceBundle getNext(UErrorCode& status); + +/** + * Returns the next string in a resource or NULL if there are no more resources + * to iterate over. + * + * @param status fills in the outgoing error code + * @return an UnicodeString object. + * @draft + */ + UnicodeString getNextString(UErrorCode& status); +/** + * Returns the next string in a resource or NULL if there are no more resources + * to iterate over. + * + * @param key fill in for key associated with this string + * @param status fills in the outgoing error code + * @return an UnicodeString object. + * @draft + */ + UnicodeString getNextString(const char ** key, UErrorCode& status); + +/** + * Returns the resource in a resource at the specified index. + * + * @param index an index to the wanted resource. + * @param status fills in the outgoing error code + * @return ResourceBundle object. If there is an error, resource is invalid. + * @draft + */ + ResourceBundle get(int32_t index, UErrorCode& status) const; + +/** + * Returns the string in a given resource at the specified index. + * + * @param index an index to the wanted string. + * @param status fills in the outgoing error code + * @return an UnicodeString object. If there is an error, string is bogus + * @draft + */ + UnicodeString getStringEx(int32_t index, UErrorCode& status) const; + +/** + * Returns a resource in a resource that has a given key. This procedure works only with table + * resources. + * + * @param key a key associated with the wanted resource + * @param status fills in the outgoing error code. + * @return ResourceBundle object. If there is an error, resource is invalid. + * @draft + */ + ResourceBundle get(const char* key, UErrorCode& status) const; + +/** + * Returns a string in a resource that has a given key. This procedure works only with table + * resources. + * + * @param key a key associated with the wanted string + * @param status fills in the outgoing error code + * @return an UnicodeString object. If there is an error, string is bogus + * @draft + */ + UnicodeString getStringEx(const char* key, UErrorCode& status) const; + /** * Returns the contents of a string resource. Resource data is undifferentiated * Unicode text. The resource file may contain quoted strings or escape sequences; * these will be parsed prior to the data's return. - * [THIS FUNCTION IS DERECATED; USE THE OVERLOAD BELOW INSTEAD] + * [THIS FUNCTION IS DEPRECATED; USE THE OVERLOAD BELOW INSTEAD] * * @param resourceTag The resource tag of the string resource the caller wants * @param theString Receives the actual data in the resource * @param err Set to U_MISSING_RESOURCE_ERROR if a resource with the * specified tag couldn't be found. - * @draft - */ + * @deprecated removed void getString( const char *resourceTag, UnicodeString& theString, UErrorCode& err) const; + */ /** * Returns the contents of a string resource. Resource data is undifferentiated @@ -226,8 +338,8 @@ public: * @param err Set to U_MISSING_RESOURCE_ERROR if a resource with the * specified tag couldn't be found. * @return A pointer to the string from the resource bundle, or NULL if there was - * an error. - * @draft + * an error.(its lifetime is that of the resource bundle.) + * @deprecated to be removed in first release in 2001 */ const UnicodeString* getString( const char *resourceTag, UErrorCode& err) const; @@ -248,8 +360,8 @@ public: * specified tag couldn't be found. * @return The resource requested, as a pointer to an array of * UnicodeStrings. The caller does not own the storage and - * must not delete it. - * @draft + * must not delete it. (its lifetime is that of the resource bundle.) + * @deprecated to be removed in first release in 2001 */ const UnicodeString* getStringArray( const char *resourceTag, int32_t& numArrayItems, @@ -268,12 +380,12 @@ public: * @param theArrayItem Receives the actual text of the desired array item. * @param err Set to U_MISSING_RESOURCE_ERROR if a resource with the * specified tag couldn't be found, or if the index was out of range. - * @draft - */ + * @deprecated removed void getArrayItem( const char *resourceTag, int32_t index, UnicodeString& theArrayItem, UErrorCode& err) const; + */ /** * Returns a single item from a string-array resource. This will return the contents @@ -286,8 +398,9 @@ public: * wants to extract from the resource. * @param err Set to U_MISSING_RESOURCE_ERROR if a resource with the * specified tag couldn't be found, or if the index was out of range. - * @return A pointer to the text of the array item, or NULL is there was an error. - * @draft + * @return A pointer to the text of the array item, or NULL is there was an error. + * (its lifetime is that of the resource bundle.) + * @deprecated to be removed in first release in 2001 */ const UnicodeString* getArrayItem( const char *resourceTag, int32_t index, @@ -308,8 +421,9 @@ public: * @param err Set to U_MISSING_RESOURCE_ERROR if a resource with the * specified tag couldn't be found. * @return The resource requested, as a UnicodeStrings**. The caller - * does not own the storage and must not delete it. - * @draft + * does not own the storage and must not delete it. (its lifetime + * is that of the resource bundle.) + * @deprecated to be removed in first release in 2001 */ const UnicodeString** get2dArray(const char *resourceTag, int32_t& rowCount, @@ -332,13 +446,13 @@ public: * @param err Set to U_MISSING_RESOURCE_ERROR if a resource with the * specified tag couldn't be found, if the resource data was in * the wrong format, or if either index is out of bounds. - * @draft - */ + * @deprecated removed void get2dArrayItem(const char *resourceTag, int32_t rowIndex, int32_t columnIndex, UnicodeString& theArrayItem, UErrorCode& err) const; + */ /** * Return a single string from a 2-dimensional array resource. If the resource does @@ -355,7 +469,8 @@ public: * specified tag couldn't be found, if the resource data was in * the wrong format, or if either index is out of bounds. * @return A pointer to the text of the array item, or NULL is there was an error. - * @draft + * (its lifetime is that of the resource bundle.) + * @deprecated to be removed in first release in 2001 */ const UnicodeString* get2dArrayItem( const char *resourceTag, int32_t rowIndex, @@ -376,12 +491,12 @@ public: * @param err Set to U_MISSING_RESOURCE_ERROR if a resource with the * specified resource tag couldn't be found, or if an item * with the specified item tag couldn't be found in the resource. - * @draft - */ + * @deprecated removed void getTaggedArrayItem( const char *resourceTag, const UnicodeString& itemTag, UnicodeString& theArrayItem, UErrorCode& err) const; + */ /** * Returns a single item from a tagged-array resource This will return the contents @@ -396,7 +511,8 @@ public: * specified resource tag couldn't be found, or if an item * with the specified item tag coldn't be found in the resource. * @return A pointer to the text of the array item, or NULL is there was an error. - * @draft + * (its lifetime is that of the resource bundle.) + * @deprecated to be removed in first release in 2001 */ const UnicodeString* getTaggedArrayItem( const char *resourceTag, const UnicodeString& itemTag, @@ -423,7 +539,7 @@ public: * items and itemTags. * @param err Set to U_MISSING_RESOURCE_ERROR if a resource with the * specified tag couldn't be found. - * @draft + * @deprecated to be removed in first release in 2001 */ void getTaggedArray( const char *resourceTag, UnicodeString*& itemTags, @@ -461,47 +577,12 @@ public: const Locale &getLocale(void) const ; private: - class U_COMMON_API PathInfo { - public: - PathInfo(); - PathInfo(const PathInfo& source); - PathInfo(const UnicodeString& path); - PathInfo(const UnicodeString& path, const UnicodeString& suffix); - PathInfo(const wchar_t* path, const wchar_t* suffix); - ~PathInfo(); + UResourceBundle *resource; + void constructForLocale(const UnicodeString& path, const Locale& locale, UErrorCode& error); + void constructForLocale(const wchar_t* path, const Locale& locale, UErrorCode& error); + void initItemCache(UErrorCode& error); - PathInfo& operator=(const PathInfo& source); - - bool_t fileExists(const UnicodeString& localeName) const; - UnicodeString makeCacheKey(const UnicodeString& localeName) const; - UnicodeString makeHashkey(const UnicodeString& localeName) const; - FileStream* openFile(const UnicodeString& localeName) const; - - private: - static const UChar kSeparator; - UnicodeString fPrefix; - UnicodeString fSuffix; - wchar_t* fWPrefix; - wchar_t* fWSuffix; - }; - -private: - friend class Locale; friend class RuleBasedCollator; - friend int32_t T_ResourceBundle_countArrayItemsImplementation(const ResourceBundle* resourceBundle, - const char* resourceKey, - UErrorCode& err) ; - friend const UnicodeString** listInstalledLocalesImplementation(const char* path, - int32_t* numInstalledLocales); - friend void getTaggedArrayUCharsImplementation( - const ResourceBundle* bundle, - const char *resourceTag, - UChar const** itemTags, - UChar const** items, - int32_t maxItems, - int32_t& numItems, - UErrorCode& err); - /** * This constructor is used by Collation to load a resource bundle from a specific @@ -512,155 +593,15 @@ private: const char *localeName, UErrorCode& status); - /** - * Return a list of all installed locales. This function returns a list of the IDs - * of all locales represented in the directory specified by this ResourceBundle. It - * depends on that directory having an "Index" tagged-list item in its "index.txt" - * file; it parses that list to determine its return value (therefore, that list - * also has to be up to date). This function is static. - * - * This function is the implementation of the Locale::listInstalledLocales() - * function. It's private because the API for it real;ly belongs in Locale. - * - * @param path The path to the locale data files. The function will - * look here for "index.txt". - * @param numInstalledLocales Receives the number of installed locales, according - * to the Index resource in index.txt. - * @return A list of the installed locales, as a pointer to an - * array of UnicodeStrings. This storage is not owned by - * the caller, who must not delete it. The information - * in this list is derived from the Index resource in - * default.txt, which must be kept up to date. - */ - static const UnicodeString* listInstalledLocales(const UnicodeString& path, - int32_t& numInstalledLocales); - - /** - * Retrieve a ResourceBundle from the cache. Return NULL if not found. - */ - static const UHashtable* getFromCache(const PathInfo& path, - const UnicodeString& localeName, - ResourceBundleCache* someCache); - - static const UHashtable* getFromCacheWithFallback(const PathInfo& path, - const UnicodeString& desiredLocale, - UnicodeString& returnedLocale, - ResourceBundleCache* someCache, - UErrorCode& error); - - /** - * Handlers which are passed to parse() have this signature. - */ - typedef void (*Handler)(const UnicodeString& localeName, - UHashtable* hashtable, - void* context, - ResourceBundleCache* someCache); - - /** - * Parse a file, storing the resource data in the cache. - */ - static void parse(const PathInfo& path, - const UnicodeString& localeName, - Handler handler, - void* context, - ResourceBundleCache* someCache, - UErrorCode &error); - - /** - * If the given file exists and has not been parsed, then parse it (caching the - * resultant data) and return true. - */ - static bool_t parseIfUnparsed(const PathInfo& path, - const UnicodeString& locale, - ResourceBundleCache* fCache, - VisitedFileCache* vCache, - UErrorCode& error); - - const UHashtable* getHashtableForLocale(const UnicodeString& localeName, - UnicodeString& returnedLocale, - UErrorCode& err); - - const UHashtable* getHashtableForLocale(const UnicodeString& desiredLocale, - UErrorCode& error); - - const ResourceBundleData* getDataForTag(const char *tag, - UErrorCode& err) const; - - void constructForLocale(const PathInfo& path, - const Locale& locale, - UErrorCode& error); - - static void addToCache(const UnicodeString& localeName, - UHashtable* hashtable, - void* context, - ResourceBundleCache* someCache); - - static void saveCollationHashtable(const UnicodeString& localeName, - UHashtable* hashtable, - void* context, - ResourceBundleCache* cache); private: - /** - * This internal class iterates over the fallback and/or default locales. It - * progresses as follows: Specific: language+country+variant language+country - * language Default: language+country+variant language+country language Root: - */ - class LocaleFallbackIterator - { - public: - LocaleFallbackIterator(const UnicodeString& startingLocale, - const UnicodeString& root, - bool_t useDefaultLocale); + static void U_CALLCONV deleteValue(void* value); + Locale fRealLocale; - const UnicodeString& getLocale(void) const { return fLocale; } - - bool_t nextLocale(UErrorCode& status); - - private: - void chopLocale(void); - - UnicodeString fLocale; - UnicodeString fDefaultLocale; - UnicodeString fRoot; - bool_t fUseDefaultLocale; - bool_t fTriedDefaultLocale; - bool_t fTriedRoot; - }; - -private: + UHashtable* fItemCache; static const char* kDefaultSuffix; static const int32_t kDefaultSuffixLen; static const char* kDefaultFilename; static const char* kDefaultLocaleName; - static const char* kIndexLocaleName; - static const char* kIndexFilename; - static const char* kIndexTag; - - static const char* kDefaultMinorVersion; - static const char* kVersionSeparator; - static const char* kVersionTag; - - static ResourceBundleCache* fgUserCache; - static VisitedFileCache* fgUserVisitedFiles; - - ResourceBundleCache* fgCache; - VisitedFileCache* fgVisitedFiles; - - /** - * Data members. The ResourceBundle object is kept lightweight by having the fData[] - * array entries be non-owned pointers. The cache (fgCache) owns the entries and - * will delete them at static destruction time. - */ - PathInfo fPath; - - enum { kDataCount = 4 }; - const UHashtable* fData[kDataCount]; // These aren't const if fIsDataOwned is true - bool_t fLoaded[kDataCount]; - UErrorCode fDataStatus[kDataCount]; // Returns the appropriate error code for each data table. - bool_t fIsDataOwned; - Locale fRealLocale; - LocaleFallbackIterator* fLocaleIterator; - char* fVersionID; }; #endif diff --git a/icu4c/source/common/unicode/ures.h b/icu4c/source/common/unicode/ures.h index d9e01199ccf..c490599ab40 100644 --- a/icu4c/source/common/unicode/ures.h +++ b/icu4c/source/common/unicode/ures.h @@ -23,8 +23,6 @@ #define URES_H #include "unicode/utypes.h" - - #include "unicode/uloc.h" /** @@ -116,9 +114,22 @@ /** A UResourceBundle. * For usage in C programs. */ -typedef void* UResourceBundle; +struct UResourceBundle; + +typedef struct UResourceBundle UResourceBundle; + +typedef enum { + RES_STRING=0, + RES_BINARY=1, + RES_TABLE=2, + + RES_INT=7, + RES_ARRAY=8, + + RES_INT_VECTOR=14, + RES_RESERVED=15 +} UResType; - /** * Functions to create and destroy resource bundles. */ @@ -186,17 +197,18 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_openW(const wchar_t* path, * could be U_MISSING_RESOURCE_ERROR if the key is not found * could be a non-failing error * e.g.: U_USING_FALLBACK_ERROR,U_USING_DEFAULT_ERROR - * @return: a library-owned zero-terminated unicode string (its lifetime + * @return a library-owned zero-terminated unicode string (its lifetime * is that of the resource bundle.) * @see ures_getArrayItem * @see ures_get2dArrayItem * @see ures_getTaggedItem - *@draft + * @deprecated */ U_CAPI const UChar* U_EXPORT2 ures_get(const UResourceBundle* resourceBundle, const char* resourceTag, UErrorCode* status); + /** * Returns a resource string which is part of an array, given a resource bundle * a key to the array and the index of the desired string. @@ -213,13 +225,14 @@ U_CAPI const UChar* U_EXPORT2 ures_get(const UResourceBundle* resourceBundle, * @see ures_get * @see ures_get2dArrayItem * @see ures_getTaggedItem - *@draft + * @deprecated */ U_CAPI const UChar* U_EXPORT2 ures_getArrayItem(const UResourceBundle* resourceBundle, const char* resourceTag, int32_t resourceIndex, UErrorCode* status); + /** * Returns a resource string which is part of a 2D array, given a resource bundle * a key to the array and the index pair of the desired string. @@ -237,7 +250,7 @@ U_CAPI const UChar* U_EXPORT2 ures_getArrayItem(const UResourceBundle* resou * @see ures_get * @see ures_getArrayItem * @see ures_getTaggedItem - *@draft + * @deprecated */ U_CAPI const UChar* U_EXPORT2 ures_get2dArrayItem(const UResourceBundle* resourceBundle, @@ -262,7 +275,7 @@ U_CAPI const UChar* U_EXPORT2 ures_get2dArrayItem(const UResourceBundle* resou * @see ures_get * @see ures_getArrayItem * @see ures_get2dItem - *@draft + * @deprecated */ U_CAPI const UChar* U_EXPORT2 ures_getTaggedArrayItem(const UResourceBundle* resourceBundle, @@ -271,7 +284,6 @@ U_CAPI const UChar* U_EXPORT2 ures_getTaggedArrayItem(const UResourceBundle* r UErrorCode* status); - /** * Returns the number of strings/arrays in resource bundles. * @@ -306,9 +318,10 @@ U_CAPI int32_t U_EXPORT2 ures_countArrayItems(const UResourceBundle* resourceBun * e.g.: U_USING_FALLBACK_ERROR,U_USING_DEFAULT_ERROR * @see ures_open * @see ures_openW - *@draft + * @draft */ U_CAPI void U_EXPORT2 ures_close(UResourceBundle* resourceBundle); + /** * Return the version number associated with this ResourceBundle. This version * number is a string of the form MAJOR.MINOR, where MAJOR is the version number of @@ -325,8 +338,9 @@ U_CAPI void U_EXPORT2 ures_close(UResourceBundle* resourceBundle); * representing the code version, and n is the minor version number, * representing the resource data file. The caller does not own this * string. - *@draft + * @draft */ + U_CAPI const char* U_EXPORT2 ures_getVersionNumber(const UResourceBundle* resourceBundle); /** @@ -334,8 +348,159 @@ U_CAPI const char* U_EXPORT2 ures_getVersionNumber(const UResourceBundle* reso * @param resourceBundle: resource bundle in question * @param status: just for catching illegal arguments * @return A Locale name - *@draft + * @draft */ U_CAPI const char* ures_getLocale(const UResourceBundle* resourceBundle, UErrorCode* status); + + +/** New API */ +U_CAPI void ures_openFillIn(UResourceBundle *r, const char* path, + const char* localeID, UErrorCode* status); + +/** + * returns a string from a string resource type + * + * @param resourceBundle: a string resource + * @param len: fills in the length of resulting string + * @param status: fills in the outgoing error code + * could be U_MISSING_RESOURCE_ERROR if the key is not found + * could be a non-failing error + * e.g.: U_USING_FALLBACK_ERROR,U_USING_DEFAULT_ERROR + * @return a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file. + * @draft + */ +U_CAPI const UChar* U_EXPORT2 ures_getString(const UResourceBundle* resourceBundle, int32_t* len, + UErrorCode* status); + +/** + * Returns the size of a resource. Size for scalar types is always 1, and for vector/table types is + * the number of child resources. + * + * @param resourceBundle: a resource + * @return number of resources in a given resource. + * @draft + */ +U_CAPI int32_t U_EXPORT2 ures_getSize(UResourceBundle *resourceBundle); + +/** + * Returns the type of a resource. Available types are defined in enum UResType + * + * @param resourceBundle: a resource + * @return type of the given resource. + * @draft + */ +U_CAPI UResType U_EXPORT2 ures_getType(UResourceBundle *resourceBundle); + +/** + * Returns the key associated with a given resource. Not all the resources have a key - only + * those that are members of a table. + * + * @param resourceBundle: a resource + * @return a key associated to this resource, or NULL if it doesn't have a key + * @draft + */ +U_CAPI const char * U_EXPORT2 ures_getKey(UResourceBundle *resB); + +/* ITERATION API + This API provides means for iterating through a resource +*/ + +/** + * Resets the internal context of a resource so that iteration starts from the first element. + * + * @param resourceBundle: a resource + * @draft + */ +U_CAPI void U_EXPORT2 ures_resetIterator(UResourceBundle *resourceBundle); + +/** + * Checks whether the given resource has another element to iterate over. + * + * @param resourceBundle a resource + * @return TRUE if there are more elements, FALSE if there is no more elements + * @draft + */ +U_CAPI bool_t U_EXPORT2 ures_hasNext(UResourceBundle *resourceBundle); + +/** + * Returns the next resource in a given resource or NULL if there are no more resources + * to iterate over. Features a fill-in parameter. + * + * @param resourceBundle a resource + * @param fillIn if NULL a new UResourceBundle struct is allocated and must be deleted by the caller. + * Alternatively, you can supply a struct to be filled by this function. + * @param status fills in the outgoing error code + * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it + * @draft + */ +U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resourceBundle, UResourceBundle *fillIn, UErrorCode *status); + +/** + * Returns the next string in a given resource or NULL if there are no more resources + * to iterate over. + * + * @param resourceBundle a resource + * @param len fill in length of the string + * @param key fill in for key associated with this string + * @param status fills in the outgoing error code + * @return a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file. + * @draft + */ +U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resourceBundle, int32_t* len, const char ** key, UErrorCode *status); + +/** + * Returns the resource in a given resource at the specified index. Features a fill-in parameter. + * + * @param resourceBundle a resource + * @param indexR an index to the wanted resource. + * @param fillIn if NULL a new UResourceBundle struct is allocated and must be deleted by the caller. + * Alternatively, you can supply a struct to be filled by this function. + * @param status fills in the outgoing error code + * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it + * @draft + */ +U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resourceBundle, int32_t indexR, UResourceBundle *fillIn, UErrorCode *status); + +/** + * Returns the string in a given resource at the specified index. + * + * @param resourceBundle a resource + * @param indexS an index to the wanted string. + * @param len fill in length of the string + * @param status fills in the outgoing error code + * @return a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file. + * @draft + */ +U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB, int32_t indexS, int32_t* len, UErrorCode *status); + +/** + * Returns a resource in a given resource that has a given key. This procedure works only with table + * resources. Features a fill-in parameter. + * + * @param resourceBundle a resource + * @param key a key associated with the wanted resource + * @param fillIn if NULL a new UResourceBundle struct is allocated and must be deleted by the caller. + * Alternatively, you can supply a struct to be filled by this function. + * @param status fills in the outgoing error code. + * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it + * @draft + */ +U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resourceBundle, const char* key, UResourceBundle *fillIn, UErrorCode *status); + +/** + * Returns a string in a given resource that has a given key. This procedure works only with table + * resources. + * + * @param resourceBundle a resource + * @param key a key associated with the wanted string + * @param len fill in length of the string + * @param status fills in the outgoing error code + * @return a pointer to a zero-terminated UChar array which lives in a memory mapped/DLL file. + * @draft + */ +U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, const char* key, int32_t* len, UErrorCode *status); + + + #endif /*_URES*/ /*eof*/ diff --git a/icu4c/source/common/unicode/utypes.h b/icu4c/source/common/unicode/utypes.h index fa856f54782..7e7aa33d1e7 100644 --- a/icu4c/source/common/unicode/utypes.h +++ b/icu4c/source/common/unicode/utypes.h @@ -232,6 +232,7 @@ enum UErrorCode { U_INVALID_TABLE_FILE = 14, /* Conversion table file not found*/ U_BUFFER_OVERFLOW_ERROR = 15, /* A result would not fit in the supplied buffer */ U_UNSUPPORTED_ERROR = 16, /* Requested operation not supported in current context */ + U_RESOURCE_TYPE_MISMATCH = 17, /* an operation is requested over a resource that does not support it*/ U_ERROR_LIMIT }; diff --git a/icu4c/source/common/uresbund.c b/icu4c/source/common/uresbund.c new file mode 100644 index 00000000000..383161cde24 --- /dev/null +++ b/icu4c/source/common/uresbund.c @@ -0,0 +1,1107 @@ +/* +******************************************************************************* +* Copyright (C) 1997-1999, International Business Machines Corporation and * +* others. All Rights Reserved. * +******************************************************************************* +* +* File CRESBUND.CPP +* +* Modification History: +* +* Date Name Description +* 04/01/97 aliu Creation. +* 06/14/99 stephen Removed functions taking a filename suffix. +* 07/20/99 stephen Changed for UResourceBundle typedef'd to void* +* 11/09/99 weiv Added ures_getLocale() +* March 2000 weiv Total overhaul - using data in DLLs +******************************************************************************* +*/ + +#include "uresimp.h" +#include + +/* this is just for internal purposes. DO NOT USE! */ +static void entryCloseInt(UResourceDataEntry *resB); +U_CAPI entryClose(UResourceDataEntry *resB); + + +/* Static cache for already opened resource bundles - mostly for keeping fallback info */ +static UHashtable *cache = NULL; +static bool_t isMutexInited = FALSE; +static UMTX resbMutex = NULL; + +/* INTERNAL: hashes an entry */ +int32_t hashEntry(const void *parm) { + UResourceDataEntry *b = (UResourceDataEntry *)parm; + return uhash_hashChars(b->fName)+37*uhash_hashChars(b->fPath); +} + +/* INTERNAL: compares two entries */ +bool_t compareEntries(const void *p1, const void *p2) { + UResourceDataEntry *b1 = (UResourceDataEntry *)p1; + UResourceDataEntry *b2 = (UResourceDataEntry *)p2; + + return(uhash_compareChars(b1->fName, b2->fName) & + uhash_compareChars(b1->fPath, b2->fPath)); +} + + +/** + * Internal function, gets parts of locale name according + * to the position of '_' character + */ +bool_t chopLocale(char *name) { + char *i = uprv_strrchr(name, '_'); + + if(i != NULL) { + *i = '\0'; + return TRUE; + } + + return FALSE; +} + +/** + * Internal function. Tries to find a resource in given Resource + * Bundle, as well as in its parents + */ +const ResourceData *getFallbackData(const UResourceBundle* resBundle, const char* * resTag, Resource *res, UErrorCode *status) { + const ResourceData *result = NULL; + const UResourceDataEntry *resB = resBundle->fData; + int32_t i = 0; + *res = RES_BOGUS; + if(resB != NULL) { + if(resB->fBogus == U_ZERO_ERROR) { /* if this resource is real, */ + *res = res_getResource(&(resB->fData), *resTag); /* try to get data from there */ + i++; + } + if(resBundle->fHasFallback == TRUE) { + while(*res == RES_BOGUS && resB->fParent != NULL) { /* Otherwise, we'll look in parents */ + resB = resB->fParent; + if(resB->fBogus == U_ZERO_ERROR) { + i++; + *res = res_getResource(&(resB->fData), *resTag); + } + } + } + + if(*res != RES_BOGUS) { /* If the resource is found in parents, we need to adjust the error */ + if(i>1) { + if(uprv_strcmp(resB->fName, uloc_getDefault())==0 || uprv_strcmp(resB->fName, kRootLocaleName)==0) { + *status = U_USING_DEFAULT_ERROR; + } else { + *status = U_USING_FALLBACK_ERROR; + } + } + return (&(resB->fData)); + } else { /* If resource is not found, we need to give an error */ + *status = U_MISSING_RESOURCE_ERROR; + return NULL; + } + } else { + *status = U_MISSING_RESOURCE_ERROR; + return NULL; + } +} + +/** INTERNAL: Initializes the cache for resources */ +void initCache(UErrorCode *status) { + if(isMutexInited == FALSE) { + umtx_lock(NULL); + if(isMutexInited == FALSE) { + umtx_init(&resbMutex); + isMutexInited = TRUE; + } + umtx_unlock(NULL); + } + if(cache == NULL) { + UHashtable *newCache = uhash_open(hashEntry, compareEntries, status); + if (U_FAILURE(*status)) { + return; + } + umtx_lock(&resbMutex); + if(cache == NULL) { + cache = newCache; + newCache = NULL; + } + umtx_unlock(&resbMutex); + if(newCache != NULL) { + uhash_close(newCache); + } + } +} + +/** INTERNAL: sets the name (locale) of the resource bundle to given name */ + +void setEntryName(UResourceDataEntry *res, char *name, UErrorCode *status) { + if(res->fName != NULL) { + uprv_free(res->fName); + } + res->fName = (char *)uprv_malloc(sizeof(char)*uprv_strlen(name)+1); + if(res->fName == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + } else { + uprv_strcpy(res->fName, name); + } +} + +/** + * INTERNAL: Inits and opens an entry from a data DLL. + */ +UResourceDataEntry *init_entry(const char *localeID, const char *path, UErrorCode *status) { + UResourceDataEntry *r = NULL; + UResourceDataEntry find; + int32_t hashValue; + char name[96]; + const char *myPath = NULL; + + if(U_FAILURE(*status)) { + return NULL; + } + + /* here we try to deduce the right locale name */ + if(localeID == NULL) { /* if localeID is NULL, we're trying to open default locale */ + uprv_strcpy(name, uloc_getDefault()); + } else if(uprv_strlen(localeID) == 0) { /* if localeID is "" then we try to open root locale */ + uprv_strcpy(name, kRootLocaleName); + } else { /* otherwise, we'll open what we're given */ + uprv_strcpy(name, localeID); + } + + if(path != NULL) { /* if we actually have path, we'll use it */ + if(uprv_strcmp(path, u_getDataDirectory()) != 0) { /* unless it is system default path */ + myPath = path; + } + } + + find.fName = name; + find.fPath = (char *)myPath; + + /* calculate the hash value of the entry */ + hashValue = hashEntry((const void *)&find); + + /* check to see if we already have this entry */ + r = (UResourceDataEntry *)uhash_get(cache, &find); + + if(r != NULL) { /* if the entry is already in the hash table */ + r->fCountExisting++; /* we just increase it's reference count */ + *status = r->fBogus; /* and set returning status */ + } else { /* otherwise, we'll try to construct a new entry */ + bool_t result = FALSE; + + r = (UResourceDataEntry *) uprv_malloc(sizeof(UResourceDataEntry)); + + if(r == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + r->fCountExisting = 1; + + r->fName = NULL; + setEntryName(r, name, status); + + r->fPath = NULL; + if(myPath != NULL && !U_FAILURE(*status)) { + r->fPath = (char *)uprv_malloc(sizeof(char)*uprv_strlen(myPath)+1); + if(r->fPath == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + } else { + uprv_strcpy(r->fPath, myPath); + } + } + + r->fHashKey = hashValue; + r->fParent = NULL; + r->fData.data = NULL; + r->fData.pRoot = NULL; + r->fData.rootRes = 0; + r->fBogus = U_ZERO_ERROR; + + /* this is the acutal loading - returns bool true/false */ + result = res_load(&(r->fData), r->fPath, r->fName, status); + + if (result == FALSE || U_FAILURE(*status)) { + /* we have no such entry in dll, so it will always use fallback */ + *status = U_USING_FALLBACK_ERROR; + r->fBogus = U_USING_FALLBACK_ERROR; + } else { /* if we have a regular entry */ + /* handle the alias by trying to get out the %%Alias tag.*/ + char aliasName[100]; + int32_t aliasLen; + UErrorCode internal = U_ZERO_ERROR; + /* We'll try to get alias string from the bundle */ + Resource aliasres = res_getResource(&(r->fData), "%%ALIAS"); + const UChar *alias = res_getString(&(r->fData), aliasres, &aliasLen); + if(alias != NULL && aliasLen > 0) { /* if there is actual alias - unload and load new data */ + u_UCharsToChars(alias, aliasName, u_strlen(alias)+1); + res_unload(&(r->fData)); + res_load(&(r->fData), r->fPath, aliasName, status); + } + } + + { + UResourceDataEntry *oldR = NULL; + if((oldR = (UResourceDataEntry *)uhash_get(cache, r)) == NULL) { /* if the data is not cached */ + /* just insert it in the cache */ + uhash_put(cache, (void *)r, r, status); + } else { + /* somebody have already inserted it while we were working, discard newly opened data */ + /* this part is probably obsolete since we check cache in locked state */ + uprv_free(r->fName); + if(r->fPath != NULL) { + uprv_free(r->fPath); + } + uprv_free(r); + r = oldR; + r->fCountExisting++; + } + } + } + return r; +} + +UResourceDataEntry *entryOpen(const char* path, const char* localeID, UErrorCode* status) { + UErrorCode initstatus = U_ZERO_ERROR; + UResourceDataEntry *r = NULL; + UResourceDataEntry *t1 = NULL; + UResourceDataEntry *t2 = NULL; + bool_t isDefault = FALSE; + bool_t hasRealData = FALSE; + bool_t hasChopped = FALSE; + char name[96]; + + if(U_FAILURE(*status)) { + return NULL; + } + + initCache(status); + + umtx_lock(&resbMutex); + r = init_entry(localeID, path, &initstatus); + uprv_strcpy(name, r->fName); + hasRealData = (r->fBogus == U_ZERO_ERROR); + isDefault = (uprv_strcmp(name, uloc_getDefault()) == 0); + + /*Fallback data stuff*/ + hasChopped = chopLocale(name); + t1 = r; + + while (hasChopped && t1->fParent == NULL) { + /* insert regular parents */ + t2 = init_entry(name, r->fPath, status); + hasRealData = (t2->fBogus == U_ZERO_ERROR) | hasRealData; + t1->fParent = t2; + t1 = t2; + hasChopped = chopLocale(name); + } + + if(!hasRealData && !isDefault && t1->fParent == NULL) { + /* insert default locale */ + uprv_strcpy(name, uloc_getDefault()); + t2 = init_entry(name, r->fPath, status); + hasRealData = (t2->fBogus == U_ZERO_ERROR) | hasRealData; + r->fBogus = U_USING_DEFAULT_ERROR; + isDefault = TRUE; + t1->fParent = t2; + t1 = t2; + hasChopped = chopLocale(name); + while (hasChopped && t1->fParent == NULL) { + /* insert chopped defaults */ + t2 = init_entry(name, r->fPath, status); + hasRealData = (t2->fBogus == U_ZERO_ERROR) | hasRealData; + t1->fParent = t2; + t1 = t2; + hasChopped = chopLocale(name); + } + } + + if(uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL) { + /* insert root locale */ + t2 = init_entry(kRootLocaleName, r->fPath, status); + hasRealData = (t2->fBogus == U_ZERO_ERROR) | hasRealData; + t1->fParent = t2; + t1 = t2; + } + + while(t1->fParent != NULL) { + t1->fParent->fCountExisting++; + t1 = t1->fParent; + hasRealData = (t1->fBogus == U_ZERO_ERROR) | hasRealData; + } + + if(!hasRealData) { + entryCloseInt(r); + *status = U_MISSING_RESOURCE_ERROR; + } + + umtx_unlock(&resbMutex); + + if(U_SUCCESS(*status)) { + *status = r->fBogus; + return r; + } else { + return NULL; + } +} + + +/** + * Functions to create and destroy resource bundles. + */ + +/** + * INTERNAL: This function is used to open a resource bundle + * without initializing fallback data. It is exclusively used + * for initing Collation data at this point. + */ +U_CFUNC UResourceBundle* ures_openNoFallback(const char* path, const char* localeID, UErrorCode* status) { + int32_t en_US = uprv_strcmp(localeID, "en_US"); + UResourceBundle *r = uprv_malloc(sizeof(UResourceBundle)); + if(r == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + + r->fHasFallback = FALSE; + r->fIsTopLevel = TRUE; + r->fIsStackObject = FALSE; + r->fIndex = -1; + r->fData = entryOpen(path, localeID, status); + if(U_FAILURE(*status)) { + uprv_free(r); + return NULL; + } + if(r->fData->fBogus != U_ZERO_ERROR) { + entryClose(r->fData); + uprv_free(r); + *status = U_MISSING_RESOURCE_ERROR; + return NULL; + } + + r->fKey = NULL; + r->fVersion = NULL; + r->fResData.data = r->fData->fData.data; + r->fResData.pRoot = r->fData->fData.pRoot; + r->fResData.rootRes = r->fData->fData.rootRes; + r->fRes = r->fResData.rootRes; + r->fSize = res_countArrayItems(&(r->fResData), r->fRes); + return r; +} + +UResourceBundle *init_resb_result(const ResourceData *rdata, const Resource r, const char *key, UResourceBundle *resB) { + if(resB == NULL) { + resB = uprv_malloc(sizeof(UResourceBundle)); + resB->fIsStackObject = FALSE; + } else { + resB->fIsStackObject = TRUE; + } + resB->fData = NULL; + resB->fHasFallback = FALSE; + resB->fIsTopLevel = FALSE; + resB->fIndex = -1; + resB->fKey = key; + /* + if(key != NULL) { + resB->fKey = uprv_malloc(uprv_strlen(key)+1); + uprv_strcpy(resB->fKey, key); + } else { + resB->fKey = NULL; + } + */ + resB->fVersion = NULL; + resB->fRes = r; + resB->fResData.data = rdata->data; + resB->fResData.pRoot = rdata->pRoot; + resB->fResData.rootRes = rdata->rootRes; + resB->fSize = res_countArrayItems(&(resB->fResData), resB->fRes); + return resB; +} + +UResourceBundle *copyResb(UResourceBundle *r, const UResourceBundle *original) { + bool_t isStackObject; + if(r == original) { + return r; + } + if(original != NULL) { + if(r == NULL) { + isStackObject = FALSE; + r = uprv_malloc(sizeof(UResourceBundle)); + } else { + isStackObject = TRUE; + } + uprv_memcpy(r, original, sizeof(UResourceBundle)); + r->fIsStackObject = isStackObject; + if(r->fData != NULL) { + r->fData->fCountExisting++; + } + return r; + } else { + return NULL; + } +} + +void copyResbFillIn(UResourceBundle *r, const UResourceBundle *original) { + if(r == NULL || original == NULL) { + return; + } + uprv_memcpy(r, original, sizeof(UResourceBundle)); + r->fIsStackObject = TRUE; + if(original->fData != NULL) { + r->fData->fCountExisting++; + } +} + + + +/** + * Functions to retrieve data from resource bundles. + */ + +/** + * INTERNAL: returns an array of installed locale names, according + * to the 'Index' resource bundle. The array is later deleted by + * the caller. + * This will probably be replaced by a call to new api. Also, there is a + * leak here - Resource data is malloced and loaded, but never freed and + * unloaded - REDO! + */ +/* +U_CFUNC UChar** ures_listInstalledLocales(const char* path, int32_t* count) { + UChar **result; + UErrorCode status; + bool_t opres = FALSE; + ResourceData *res = (ResourceData *)uprv_malloc(sizeof(ResourceData)); + opres = res_load(res, path, kIndexLocaleName, &status); + + if(opres == TRUE) { + int32_t i = 0; + int32_t len = 0; + Resource r = res_getStringArray(res, kIndexTag, count); + result = (UChar **)malloc(*count*sizeof(UChar *)); + for(i=0; i<*count; i++) { + *(result+i) = (UChar *)res_getStringArrayItem(res, r, i, &len); + } + return result; + } else { + count = 0; + return NULL; + } +} +*/ + +U_CAPI const UChar* U_EXPORT2 ures_getString(const UResourceBundle* resB, int32_t* len, UErrorCode* status) { + switch(RES_GET_TYPE(resB->fRes)) { + case RES_STRING: + return res_getString(&(resB->fResData), resB->fRes, len); + break; + case RES_INT: + case RES_INT_VECTOR: + case RES_BINARY: + case RES_ARRAY: + case RES_TABLE: + default: + *status = U_RESOURCE_TYPE_MISMATCH; + return NULL; + break; + } +} + +U_CAPI UResType U_EXPORT2 ures_getType(UResourceBundle *resB) { + return(RES_GET_TYPE(resB->fRes)); +} + +U_CAPI const char * U_EXPORT2 ures_getKey(UResourceBundle *resB) { + return(resB->fKey); +} + +U_CAPI int32_t U_EXPORT2 ures_getSize(UResourceBundle *resourceBundle) { + return resourceBundle->fSize; +} + +U_CAPI void U_EXPORT2 ures_resetIterator(UResourceBundle *resourceBundle){ + resourceBundle->fIndex = -1; +} + +U_CAPI bool_t U_EXPORT2 ures_hasNext(UResourceBundle *resourceBundle) { + return(resourceBundle->fIndex < resourceBundle->fSize-1); +} + +U_CAPI const UChar* U_EXPORT2 ures_getNextString(UResourceBundle *resB, int32_t* len, const char ** key, UErrorCode *status) { + Resource r = RES_BOGUS; + + if(resB->fIndex == resB->fSize-1) { + *status = U_INDEX_OUTOFBOUNDS_ERROR; + return NULL; + } else { + resB->fIndex++; + switch(RES_GET_TYPE(resB->fRes)) { + case RES_INT: + case RES_BINARY: + case RES_STRING: + return res_getString(&(resB->fResData), resB->fRes, len); + break; + case RES_TABLE: + r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, key); + if(r == RES_BOGUS && resB->fHasFallback) { + /* TODO: do the fallback */ + } + return res_getString(&(resB->fResData), r, len); + break; + case RES_ARRAY: + r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex); + if(r == RES_BOGUS && resB->fHasFallback) { + /* TODO: do the fallback */ + } + return res_getString(&(resB->fResData), r, len); + break; + case RES_INT_VECTOR: + default: + return NULL; + break; + } + } + /*return NULL;*/ +} + +U_CAPI UResourceBundle* U_EXPORT2 ures_getNextResource(UResourceBundle *resB, UResourceBundle *fillIn, UErrorCode *status) { + const char *key = NULL; + Resource r = RES_BOGUS; + +/* + if(resB->fIndex == -1) { + resB->fIndex = 0; + } +*/ + if(resB->fIndex == resB->fSize-1) { + *status = U_INDEX_OUTOFBOUNDS_ERROR; + return NULL; + } else { + resB->fIndex++; + switch(RES_GET_TYPE(resB->fRes)) { + case RES_INT: + case RES_BINARY: + case RES_STRING: + return copyResb(NULL, resB); + break; + case RES_TABLE: + r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, resB->fIndex, &key); + if(r == RES_BOGUS && resB->fHasFallback) { + /* TODO: do the fallback */ + } + return init_resb_result(&(resB->fResData), r, key, fillIn); + break; + case RES_ARRAY: + r = res_getArrayItem(&(resB->fResData), resB->fRes, resB->fIndex); + if(r == RES_BOGUS && resB->fHasFallback) { + /* TODO: do the fallback */ + } + return init_resb_result(&(resB->fResData), r, key, fillIn); + break; + case RES_INT_VECTOR: + default: + return NULL; + break; + } + } + /*return NULL;*/ +} + +U_CAPI UResourceBundle* U_EXPORT2 ures_getByIndex(const UResourceBundle *resB, int32_t indexR, UResourceBundle *fillIn, UErrorCode *status) { + const char* key = NULL; + Resource r = RES_BOGUS; + + if(indexR >= 0 && resB->fSize > indexR) { + switch(RES_GET_TYPE(resB->fRes)) { + case RES_INT: + case RES_BINARY: + case RES_STRING: + return copyResb(NULL, resB); + break; + case RES_TABLE: + r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexR, &key); + if(r == RES_BOGUS && resB->fHasFallback) { + /* TODO: do the fallback */ + } + return init_resb_result(&(resB->fResData), r, key, fillIn); + break; + case RES_ARRAY: + r = res_getArrayItem(&(resB->fResData), resB->fRes, indexR); + if(r == RES_BOGUS && resB->fHasFallback) { + /* TODO: do the fallback */ + } + return init_resb_result(&(resB->fResData), r, key, fillIn); + break; + case RES_INT_VECTOR: + default: + return NULL; + break; + } + } else { + *status = U_MISSING_RESOURCE_ERROR; + return NULL; + } +} + +U_CAPI const UChar* U_EXPORT2 ures_getStringByIndex(const UResourceBundle *resB, int32_t indexS, int32_t* len, UErrorCode *status) { + const char* key = NULL; + Resource r = RES_BOGUS; + + if(indexS >= 0 && resB->fSize > indexS) { + switch(RES_GET_TYPE(resB->fRes)) { + case RES_INT: + case RES_BINARY: + case RES_STRING: + return res_getString(&(resB->fResData), resB->fRes, len); + break; + case RES_TABLE: + r = res_getTableItemByIndex(&(resB->fResData), resB->fRes, indexS, &key); + if(r == RES_BOGUS && resB->fHasFallback) { + /* TODO: do the fallback */ + } + return res_getString(&(resB->fResData), r, len); + break; + case RES_ARRAY: + r = res_getArrayItem(&(resB->fResData), resB->fRes, indexS); + if(r == RES_BOGUS && resB->fHasFallback) { + /* TODO: do the fallback */ + } + return res_getString(&(resB->fResData), r, len); + break; + case RES_INT_VECTOR: + default: + return NULL; + break; + } + } else { + *status = U_MISSING_RESOURCE_ERROR; + return NULL; + } +} + +U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, const char* inKey, UResourceBundle *fillIn, UErrorCode *status) { + Resource res = RES_BOGUS; + const char *key = inKey; + + if(RES_GET_TYPE(resB->fRes) == RES_TABLE) { + int32_t t; + res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key); + if(res == RES_BOGUS) { + key = inKey; + if(resB->fHasFallback == TRUE) { + const ResourceData *rd = getFallbackData(resB, &key, &res, status); + if(U_FAILURE(*status)) { + return NULL; + } else { + return init_resb_result(rd, res, key, fillIn); + } + } else { + *status = U_MISSING_RESOURCE_ERROR; + return NULL; + } + } else { + return init_resb_result(&(resB->fResData), res, key, fillIn); + } + } else if(RES_GET_TYPE(resB->fRes) == RES_ARRAY && resB->fHasFallback == TRUE) { + /* here should go a first attempt to locate the key using index table */ + const ResourceData *rd = getFallbackData(resB, &key, &res, status); + if(U_FAILURE(*status)) { + return NULL; + } else { + return init_resb_result(rd, res, key, fillIn); + } + } else { + *status = U_RESOURCE_TYPE_MISMATCH; + return NULL; + } +} + +U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, const char* inKey, int32_t* len, UErrorCode *status) { + Resource res = RES_BOGUS; + const char* key = inKey; + + if(RES_GET_TYPE(resB->fRes) == RES_TABLE) { + int32_t t=0; + res = res_getTableItemByKey(&(resB->fResData), resB->fRes, &t, &key); + if(res == RES_BOGUS) { + key = inKey; + if(resB->fHasFallback == TRUE) { + const ResourceData *rd = getFallbackData(resB, &key, &res, status); + if(U_FAILURE(*status)) { + *status = U_MISSING_RESOURCE_ERROR; + return NULL; + } else { + return res_getString(rd, res, len); + } + } else { + *status = U_MISSING_RESOURCE_ERROR; + return NULL; + } + } else { + return res_getString(&(resB->fResData), res, len); + } + } else if(RES_GET_TYPE(resB->fRes) == RES_ARRAY && resB->fHasFallback == TRUE) { + /* here should go a first attempt to locate the key using index table */ + const ResourceData *rd = getFallbackData(resB, &key, &res, status); + if(U_FAILURE(*status)) { + *status = U_MISSING_RESOURCE_ERROR; + return NULL; + } else { + return res_getString(rd, res, len); + } + } else { + *status = U_RESOURCE_TYPE_MISMATCH; + return NULL; + } +} + + +/* TODO: clean from here down */ + +/** + * INTERNAL: Get the name of the first real locale (not placeholder) + * that has resource bundle data. + */ +U_CFUNC const char* ures_getRealLocale(const UResourceBundle* resourceBundle, UErrorCode* status) +{ + const UResourceDataEntry *resB = resourceBundle->fData; + if (status==NULL || U_FAILURE(*status)) return NULL; + if (!resourceBundle) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return NULL; + } + while(resB->fBogus != U_ZERO_ERROR && resB->fParent != NULL) { + resB = resB->fParent; + } + if(resB->fBogus == U_ZERO_ERROR) { + return resB->fName; + } else { + *status = U_INTERNAL_PROGRAM_ERROR; + return NULL; + } +} + +static void entryCloseInt(UResourceDataEntry *resB) { + UResourceDataEntry *p = resB; + + while(resB != NULL) { + p = resB->fParent; + resB->fCountExisting--; + + if(resB->fCountExisting <= 0) { +/* + uhash_remove(cache, resB); + if(resB->fBogus == U_ZERO_ERROR) { + res_unload(&(resB->fData)); + } + if(resB->fName != NULL) { + uprv_free(resB->fName); + } + if(resB->fPath != NULL) { + uprv_free(resB->fPath); + } + uprv_free(resB); +*/ + } + + resB = p; + } +} + +/** + * API: closes a resource bundle and cleans up. + */ + +U_CAPI entryClose(UResourceDataEntry *resB) { + umtx_lock(&resbMutex); + entryCloseInt(resB); + umtx_unlock(&resbMutex); +} + + +U_CFUNC const char* ures_getName(const UResourceBundle* resB) { + return resB->fData->fName; +} +U_CFUNC const char* ures_getPath(const UResourceBundle* resB) { + return resB->fData->fPath; +} +U_CFUNC const char* ures_getTag(const UResourceBundle* resB) { + return resB->fKey; +} +U_CFUNC const ResourceData * ures_getResData(const UResourceBundle* resB) { + return &(resB->fData->fData); +} + +/* OLD API implementation */ + +/** + * API: This function is used to open a resource bundle + * proper fallback chaining is executed while initialization. + * The result is stored in cache for later fallback search. + */ +U_CAPI void ures_openFillIn(UResourceBundle *r, const char* path, + const char* localeID, UErrorCode* status) { + if(r == NULL) { + *status = U_INTERNAL_PROGRAM_ERROR; + } else { + UResourceDataEntry *firstData; + r->fHasFallback = TRUE; + r->fIsTopLevel = TRUE; + r->fIsStackObject = TRUE; + r->fKey = NULL; + r->fVersion = NULL; + r->fIndex = -1; + r->fData = entryOpen(path, localeID, status); + /* this is a quick fix to get regular data in bundle - until construction is cleaned up */ + firstData = r->fData; + while(firstData->fBogus != U_ZERO_ERROR && firstData->fParent != NULL) { + firstData = firstData->fParent; + } + r->fResData.data = firstData->fData.data; + r->fResData.pRoot = firstData->fData.pRoot; + r->fResData.rootRes = firstData->fData.rootRes; + r->fRes = r->fResData.rootRes; + r->fSize = res_countArrayItems(&(r->fResData), r->fRes); + } +} +U_CAPI UResourceBundle* ures_open(const char* path, + const char* localeID, + UErrorCode* status) +{ + UResourceDataEntry *hasData = NULL; + UResourceBundle *r = uprv_malloc(sizeof(UResourceBundle)); + if(r == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + + r->fHasFallback = TRUE; + r->fIsTopLevel = TRUE; + r->fIsStackObject = FALSE; + r->fKey = NULL; + r->fVersion = NULL; + r->fIndex = -1; + r->fData = entryOpen(path, localeID, status); + if(U_FAILURE(*status)) { + uprv_free(r); + return NULL; + } + + hasData = r->fData; + while(hasData->fBogus != U_ZERO_ERROR) { + hasData = hasData->fParent; + if(hasData == NULL) { + entryClose(r->fData); + uprv_free(r); + *status = U_MISSING_RESOURCE_ERROR; + return NULL; + } + } + + r->fResData.data = hasData->fData.data; + r->fResData.pRoot = hasData->fData.pRoot; + r->fResData.rootRes = hasData->fData.rootRes; + r->fRes = r->fResData.rootRes; + r->fSize = res_countArrayItems(&(r->fResData), r->fRes); + + return r; +} + +U_CAPI UResourceBundle* ures_openW(const wchar_t* myPath, + const char* localeID, + UErrorCode* status) +{ + char path[100]; + UResourceBundle *r; + size_t tempSize = uprv_wcstombs(NULL, myPath, ((size_t)-1) >> 1); + /*char *temp = new char[tempSize + 1];*/ + + tempSize = uprv_wcstombs(path, myPath, tempSize); + path[tempSize] = 0; + + /*u_UCharsToChars(myPath, path, uprv_wcslen(myPath)+1);*/ + + r = ures_open(path, localeID, status); + + if (r == FALSE || U_FAILURE(*status)) { + return NULL; + } + + return r; +} + +U_CAPI const UChar* ures_get( const UResourceBundle* resB, + const char* resourceTag, + UErrorCode* status) +{ + int32_t len = 0; + return ures_getStringByKey(resB, resourceTag, &len, status); +} + +U_CAPI const UChar* ures_getArrayItem(const UResourceBundle* resB, + const char* resourceTag, + int32_t resourceIndex, + UErrorCode* status) +{ + UResourceBundle res; + ures_getByKey(resB, resourceTag, &res, status); + if(U_SUCCESS(*status)) { + int32_t len = 0; + const UChar *r = ures_getStringByIndex(&res, resourceIndex, &len, status); + ures_close(&res); + return r; + } else { + return NULL; + } +} + +U_CAPI const UChar* ures_get2dArrayItem(const UResourceBundle* resB, + const char* resourceTag, + int32_t rowIndex, + int32_t columnIndex, + UErrorCode* status) +{ + UResourceBundle res; + ures_getByKey(resB, resourceTag, &res, status); + if(U_SUCCESS(*status)) { + UResourceBundle res2; + ures_getByIndex(&res, rowIndex, &res2, status); + ures_close(&res); + if(U_SUCCESS(*status)) { + int32_t len = 0; + const UChar *r = ures_getStringByIndex(&res2, columnIndex, &len, status); + ures_close(&res2); + return r; + } else { + return NULL; + } + } else { + return NULL; + } +} + +U_CAPI const UChar* ures_getTaggedArrayItem(const UResourceBundle* resB, + const char* resourceTag, + const char* itemTag, + UErrorCode* status) +{ + UResourceBundle res; + ures_getByKey(resB, resourceTag, &res, status); + if(U_SUCCESS(*status)) { + int32_t len = 0; + const UChar *r = ures_getStringByKey(&res, itemTag, &len, status); + ures_close(&res); + return r; + } else { + return NULL; + } +} + +/** + * API: Counts members. For arrays and tables, returns number of resources. + * For strings, returns 1. + */ +U_CAPI int32_t ures_countArrayItems(const UResourceBundle* resourceBundle, + const char* resourceKey, + UErrorCode* status) +{ + Resource res = RES_BOGUS; + + UResourceBundle resData; + ures_getByKey(resourceBundle, resourceKey, &resData, status); + + if(resData.fResData.data != NULL) { + return res_countArrayItems(&resData.fResData, resData.fRes); + } else { + *status = U_MISSING_RESOURCE_ERROR; + return 0; + } +} + +U_CAPI void ures_close(UResourceBundle* resB) +{ + if(resB != NULL) { + if(resB->fData != NULL) { + entryClose(resB->fData); + } + /* + if(resB->fKey != NULL) { + uprv_free(resB->fKey); + } + */ + if(resB->fVersion != NULL) { + uprv_free(resB->fVersion); + } + + if(resB->fIsStackObject == FALSE) { + uprv_free(resB); + } + } +} + +U_CAPI const char* ures_getVersionNumber(const UResourceBundle* resourceBundle) +{ + if (!resourceBundle) return NULL; + + if(resourceBundle->fVersion == NULL) { + + /* If the version ID has not been built yet, then do so. Retrieve */ + /* the minor version from the file. */ + UErrorCode status = U_ZERO_ERROR; + int32_t minor_len = 0; + + const UChar* minor_version = ures_getStringByKey(resourceBundle, kVersionTag, &minor_len, &status); + + /* Determine the length of of the final version string. This is */ + /* the length of the major part + the length of the separator */ + /* (==1) + the length of the minor part (+ 1 for the zero byte at */ + /* the end). */ + int32_t len = uprv_strlen(U_ICU_VERSION); + /* + if(U_SUCCESS(status) && minor_version.length() > 0) + { + minor_len = u_strlen(minor_version); + } + */ + len += (minor_len > 0) ? minor_len : 1 /*==uprv_strlen(kDefaultMinorVersion)*/; + ++len; /* Add length of separator */ + + /* Allocate the string, and build it up. */ + /* + 1 for zero byte */ + + + ((UResourceBundle *)resourceBundle)->fVersion = (char *)uprv_malloc(1 + len); + + uprv_strcpy(resourceBundle->fVersion, U_ICU_VERSION); + uprv_strcat(resourceBundle->fVersion, kVersionSeparator); + + if(minor_len > 0) { + u_UCharsToChars(minor_version, resourceBundle->fVersion + len - minor_len, minor_len); + /*minor_version.extract(0, minor_len, fVersionID + len - minor_len, "");*/ + resourceBundle->fVersion[len] = '\0'; + } + else { + uprv_strcat(resourceBundle->fVersion, kDefaultMinorVersion); + } + } + + return resourceBundle->fVersion; +} + +/** + * API: get the nominal name of resource bundle locale, + * regardless of wether resource bundle really exists + * or not. + */ +U_CAPI const char* ures_getLocale(const UResourceBundle* resourceBundle, UErrorCode* status) +{ + if (status==NULL || U_FAILURE(*status)) return NULL; + if (!resourceBundle) + { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return NULL; + } + return ures_getName(resourceBundle); +} + + +/* eof */ diff --git a/icu4c/source/common/uresdata.c b/icu4c/source/common/uresdata.c index 2b27c365dd0..4b72e652e76 100644 --- a/icu4c/source/common/uresdata.c +++ b/icu4c/source/common/uresdata.c @@ -16,8 +16,10 @@ #include "unicode/utypes.h" #include "cstring.h" +#include "cmemory.h" #include "unicode/udata.h" #include "uresdata.h" +#include "uresimp.h" /* * Resource access helpers @@ -40,7 +42,7 @@ * * Note that the type value for strings is 0, therefore * res itself contains the offset value. - */ + */ static const UChar nulUChar=0; static const UChar * @@ -59,12 +61,12 @@ _res_getString(Resource *pRoot, Resource res, int32_t *pLength) { * Array functions */ static Resource -_res_getArrayItem(Resource *pRoot, Resource res, int32_t index) { +_res_getArrayItem(Resource *pRoot, Resource res, int32_t indexR) { int32_t *p=(int32_t *)RES_GET_POINTER(pRoot, res); - if(index<*p) { - return ((Resource *)(p))[1+index]; + if(indexR<*p) { + return ((Resource *)(p))[1+indexR]; } else { - return RES_BOGUS; /* index>itemCount */ + return RES_BOGUS; /* indexR>itemCount */ } } @@ -79,28 +81,28 @@ _res_getArrayItem(Resource *pRoot, Resource res, int32_t index) { * 16-bit padding words. */ static const char * -_res_getTableKey(Resource *pRoot, Resource res, uint16_t index) { +_res_getTableKey(const Resource *pRoot, const Resource res, uint16_t indexS) { uint16_t *p=(uint16_t *)RES_GET_POINTER(pRoot, res); - if(index<*p) { - return RES_GET_KEY(pRoot, p[index+1]); + if(indexS<*p) { + return RES_GET_KEY(pRoot, p[indexS+1]); } else { - return NULL; /* index>itemCount */ + return NULL; /* indexS>itemCount */ } } static Resource -_res_getTableItem(Resource *pRoot, Resource res, uint16_t index) { +_res_getTableItem(const Resource *pRoot, const Resource res, uint16_t indexR) { uint16_t *p=(uint16_t *)RES_GET_POINTER(pRoot, res); uint16_t count=*p; - if(indexitemCount */ + return RES_BOGUS; /* indexR>itemCount */ } } static Resource -_res_findTableItem(Resource *pRoot, Resource res, const char *key) { +_res_findTableItem(const Resource *pRoot, const Resource res, const char *key) { uint16_t *p=(uint16_t *)RES_GET_POINTER(pRoot, res); uint16_t i, start, limit; @@ -126,6 +128,47 @@ _res_findTableItem(Resource *pRoot, Resource res, const char *key) { } } +static uint16_t +_res_findTableIndex(const Resource *pRoot, const Resource res, const char *key) { + uint16_t *p=(uint16_t *)RES_GET_POINTER(pRoot, res); + uint16_t i, start, limit; + + limit=*p++; /* number of entries */ + + /* do a binary search for the key */ + start=0; + while(start0) { + if(RES_GET_TYPE(*++r)!=RES_STRING) { + return FALSE; + } + --count; + } + return TRUE; +} + /* helper for res_load() ---------------------------------------------------- */ static bool_t @@ -166,7 +209,7 @@ res_load(ResourceData *pResData, /* currently, we accept only resources that have a Table as their roots */ if(RES_GET_TYPE(pResData->rootRes)!=RES_TABLE) { udata_close(pResData->data); - pResData->data=NULL; + pResData->data=NULL; return FALSE; } @@ -182,8 +225,9 @@ res_unload(ResourceData *pResData) { } U_CFUNC const UChar * -res_getString(ResourceData *pResData, const char *key, int32_t *pLength) { - Resource res=_res_findTableItem(pResData->pRoot, pResData->rootRes, key); +/*res_getString(const ResourceData *pResData, const char *key, int32_t *pLength) { + Resource res=_res_findTableItem(pResData->pRoot, pResData->rootRes, key);*/ +res_getString(const ResourceData *pResData, const Resource res, int32_t *pLength) { if(res!=RES_BOGUS && RES_GET_TYPE(res)==RES_STRING) { return _res_getString(pResData->pRoot, res, pLength); } else { @@ -193,7 +237,7 @@ res_getString(ResourceData *pResData, const char *key, int32_t *pLength) { } U_CFUNC Resource -res_getStringArray(ResourceData *pResData, const char *key, int32_t *pCount) { +res_getStringArray(const ResourceData *pResData, const char *key, int32_t *pCount) { Resource res=_res_findTableItem(pResData->pRoot, pResData->rootRes, key); if(res!=RES_BOGUS && RES_GET_TYPE(res)==RES_ARRAY) { Resource *p=RES_GET_POINTER(pResData->pRoot, res); @@ -201,12 +245,9 @@ res_getStringArray(ResourceData *pResData, const char *key, int32_t *pCount) { *pCount=count; /* check to make sure all items are strings */ - while(count>0) { - if(RES_GET_TYPE(*++p)!=RES_STRING) { + if(!_res_isStringArray(p)) { *pCount=0; return RES_BOGUS; - } - --count; } return res; } else { @@ -215,10 +256,180 @@ res_getStringArray(ResourceData *pResData, const char *key, int32_t *pCount) { } } + +U_CFUNC int32_t +res_countArrayItems(const ResourceData *pResData, const Resource res) { + /*Resource res=_res_findTableItem(pResData->pRoot, pResData->rootRes, key);*/ + if(res!=RES_BOGUS) { + if(RES_GET_TYPE(res)==RES_STRING) { + return 1; + } else if(RES_GET_TYPE(res)==RES_ARRAY) { + Resource *p=RES_GET_POINTER(pResData->pRoot, res); + int32_t count=*(int32_t *)p; + return count; + } else if(RES_GET_TYPE(res)==RES_TABLE) { + return res_getTableSize(pResData, res); + } + } + return 0; +} + +U_CFUNC int32_t +res_count2dArrayCols(const ResourceData *pResData, const Resource res) { + /*Resource res=_res_findTableItem(pResData->pRoot, pResData->rootRes, key);*/ + if(res!=RES_BOGUS) { + if(RES_GET_TYPE(res)==RES_ARRAY) { + Resource *p=RES_GET_POINTER(pResData->pRoot, res); + int32_t count = *(int32_t *)RES_GET_POINTER(pResData->pRoot, *(p+1)); /*Number of columns in the first row*/ + return count; + } + } + return 0; +} + +U_CFUNC Resource +res_get2DStringArray(const ResourceData *pResData, const char *key, int32_t *pRows, int32_t *pCols) { + Resource res=_res_findTableItem(pResData->pRoot, pResData->rootRes, key); + if(res!=RES_BOGUS && RES_GET_TYPE(res)==RES_ARRAY) { + Resource *p=RES_GET_POINTER(pResData->pRoot, res); + Resource *row=NULL; + int32_t row_count=*(int32_t *)p; + *pRows = row_count; + + *pCols = *(int32_t *)RES_GET_POINTER(pResData->pRoot, *(p+1)); /*Number of columns in the first row*/ + + /* check to make sure all items are strings */ + while(row_count>0) { + row = RES_GET_POINTER(pResData->pRoot, *(++p)); + if(!_res_isStringArray(row) || RES_GET_TYPE(*p)!=RES_ARRAY) { + *pRows=0; + *pCols=0; + return RES_BOGUS; + } else { + int32_t col_count=*(int32_t *)(row); + if(*pCols != col_count) { + *pRows=0; + *pCols=0; + return RES_BOGUS; + } + } + --row_count; + } + return res; + } else { + *pRows=0; + *pCols=0; + return RES_BOGUS; + } +} + +U_CFUNC Resource +res_getResource(const ResourceData *pResData, const char *key) { + return _res_findTableItem(pResData->pRoot, pResData->rootRes, key); +} + +U_CFUNC Resource +res_getTable(const ResourceData *pResData, const char *key) { + return _res_findTableItem(pResData->pRoot, pResData->rootRes, key); +} + +U_CFUNC Resource res_getArrayItem(const ResourceData *pResData, const Resource array, const int32_t indexR) { + return _res_getArrayItem(pResData->pRoot, array, indexR); +} + +U_CFUNC Resource res_getTableItemByKey(const ResourceData *pResData, const Resource table, int32_t* indexR, const char* * key) { + if(key != NULL) { + *indexR = _res_findTableIndex(pResData->pRoot, table, *key); + if(*indexR > -1) { + *key = _res_getTableKey(pResData->pRoot, table, (uint16_t)*indexR); + return _res_getTableItem(pResData->pRoot, table, (uint16_t)*indexR); + } else { + return RES_BOGUS; + } + /*return _res_findTableItem(pResData->pRoot, table, key);*/ + } else { + return RES_BOGUS; + } +} + +U_CFUNC Resource res_getTableItemByIndex(const ResourceData *pResData, const Resource table, int32_t indexR, const char * * key) { + if(indexR>-1) { + if(key != NULL) { + *key = _res_getTableKey(pResData->pRoot, table, (uint16_t)indexR); + } + return _res_getTableItem(pResData->pRoot, table, (uint16_t)indexR); + } else { + return RES_BOGUS; + } +} + +U_CFUNC int32_t res_getTableSize(const ResourceData *pResData, Resource table) { + uint16_t *p=(uint16_t *)RES_GET_POINTER(pResData->pRoot, table); + return *p; +} + +U_CFUNC void +res_getNextStringTableItem(const ResourceData *pResData, Resource table, const UChar **value, const char **key, int32_t *len, int16_t *indexS) { + Resource next; + if(*indexS == -1) { + *indexS = 0; + } + next = _res_getTableItem(pResData->pRoot, table, *indexS); + if ((next == RES_BOGUS) || (RES_GET_TYPE(next) != RES_STRING)) { + *key = NULL; + *value = NULL; + len = 0; + return; + } + *key = _res_getTableKey(pResData->pRoot, table, *indexS); + (*indexS)++; + *value = _res_getString(pResData->pRoot, next, len); +} + U_CFUNC const UChar * -res_getStringArrayItem(ResourceData *pResData, - Resource arrayRes, int32_t index, int32_t *pLength) { +res_getStringTableItem(const ResourceData *pResData, Resource table, const char *key, int32_t *len) { + Resource res = _res_findTableItem(pResData->pRoot, table, key); + if(RES_GET_TYPE(res) != RES_STRING) { + return NULL; + } + + return _res_getString(pResData->pRoot, res, len); + +} + + +U_CFUNC const UChar * +res_get2DStringArrayItem(const ResourceData *pResData, + Resource arrayRes, int32_t row, int32_t col, int32_t *pLength) { + Resource res = _res_getArrayItem(pResData->pRoot, arrayRes, row); return _res_getString(pResData->pRoot, - _res_getArrayItem(pResData->pRoot, arrayRes, index), + _res_getArrayItem(pResData->pRoot, res, col), pLength); } + +U_CFUNC const UChar * +res_getStringArrayItem(const ResourceData *pResData, + Resource arrayRes, int32_t indexS, int32_t *pLength) { + return _res_getString(pResData->pRoot, + _res_getArrayItem(pResData->pRoot, arrayRes, indexS), + pLength); +} + +U_CFUNC const char * +res_getVersion(const ResourceData *pResData) { + UDataInfo *info; + + info = uprv_malloc(sizeof(UDataInfo)); + uprv_memset(info, 0, sizeof(UDataInfo)); + + if(info == NULL) { + return NULL; + } + + udata_getInfo(pResData->data, info); + + uprv_free(info); + + return NULL; +} + diff --git a/icu4c/source/common/uresdata.h b/icu4c/source/common/uresdata.h index 63acc26bbfe..45765f6aa47 100644 --- a/icu4c/source/common/uresdata.h +++ b/icu4c/source/common/uresdata.h @@ -44,26 +44,17 @@ typedef uint32_t Resource; * * 0 Unicode String: int32_t length, UChar[length], (UChar)0, (padding) * or (empty string ("") if offset==0) - * - * 1 Integer Vector: int32_t length, int32_t[length] - * 2 Binary: int32_t length, uint8_t[length], (padding) + * 1 Binary: int32_t length, uint8_t[length], (padding) * - this value should be 16-aligned - + * 2 Table: uint16_t count, uint16_t keyStringOffsets[count], (uint16_t padding), Resource[count] * * 7 Integer: (28-bit offset is integer value) + * 8 Array: int32_t count, Resource[count] * - * 14 Array: int32_t count, Resource[count] - * 15 Table: uint16_t count, uint16_t keyStringOffsets[count], (uint16_t padding), Resource[count] + * 14 Integer Vector: int32_t length, int32_t[length] + * 15 Reserved: This value denotes special purpose resources and is for internal use. + */ -enum { - RES_STRING, - RES_INT_VECTOR, - RES_BINARY, - - RES_INT=7, - - RES_ARRAY=14, - RES_TABLE -}; /* * Structure for a single, memory-mapped ResourceBundle. @@ -95,14 +86,25 @@ res_unload(ResourceData *pResData); * Returns NULL if not found. */ U_CFUNC const UChar * -res_getString(ResourceData *pResData, const char *key, int32_t *pLength); +res_getString(const ResourceData *pResData, const Resource res, int32_t *pLength); /* * Get a Resource handle for an array of strings, and get the number of strings. * Returns RES_BOGUS if not found. */ U_CFUNC Resource -res_getStringArray(ResourceData *pResData, const char *key, int32_t *pCount); +res_getStringArray(const ResourceData *pResData, const char *key, int32_t *pCount); + +U_CFUNC Resource +res_get2DStringArray(const ResourceData *pResData, const char *key, + int32_t *pRows, int32_t *pCols); + +U_CFUNC Resource +res_getTable(const ResourceData *pResData, const char *key); + + +U_CFUNC Resource +res_getResource(const ResourceData *pResData, const char *key); /* * Get a string from a string array. @@ -110,7 +112,34 @@ res_getStringArray(ResourceData *pResData, const char *key, int32_t *pCount); * by res_getStringArray(), and that index is within bounds. */ U_CFUNC const UChar * -res_getStringArrayItem(ResourceData *pResData, - Resource arrayRes, int32_t index, int32_t *pLength); +res_getStringArrayItem(const ResourceData *pResData, + Resource arrayRes, int32_t indexS, int32_t *pLength); + +U_CFUNC const UChar * +res_get2DStringArrayItem(const ResourceData *pResData, + Resource arrayRes, int32_t row, int32_t col, int32_t *pLength); + +U_CFUNC const UChar * +res_getStringTableItem(const ResourceData *pResData, Resource table, + const char *key, int32_t *len); +U_CFUNC const char * +res_getVersion(const ResourceData *pResData); + +U_CFUNC int32_t +res_countArrayItems(const ResourceData *pResData, const Resource res); + +U_CFUNC int32_t +res_count2dArrayCols(const ResourceData *pResData, const Resource res); + +U_CFUNC void +res_getNextStringTableItem(const ResourceData *pResData, Resource table, + const UChar **value, const char **key, int32_t *len, + int16_t *indexS); + +U_CFUNC int32_t res_getTableSize(const ResourceData *pResData, Resource table); + +U_CFUNC Resource res_getArrayItem(const ResourceData *pResData, const Resource array, const int32_t indexS); +U_CFUNC Resource res_getTableItemByIndex(const ResourceData *pResData, const Resource table, int32_t indexS, const char ** key); +U_CFUNC Resource res_getTableItemByKey(const ResourceData *pResData, const Resource table, int32_t *indexS, const char* * key); #endif diff --git a/icu4c/source/common/uresimp.h b/icu4c/source/common/uresimp.h new file mode 100644 index 00000000000..2394e13a068 --- /dev/null +++ b/icu4c/source/common/uresimp.h @@ -0,0 +1,91 @@ +#ifndef URESIMP_H +#define URESIMP_H + +#include "unicode/ures.h" + +#include "unicode/uloc.h" +#include "unicode/ustring.h" +#include "cmemory.h" +#include "cstring.h" +#include "uresdata.h" +#include "uhash.h" +#include "umutex.h" + +#define kRootLocaleName "root" +#define kIndexLocaleName "index" +#define kIndexTag "InstalledLocales" + +/* + The default minor version and the version separator must be exactly one + character long. +*/ + +#define kDefaultMinorVersion "0" +#define kVersionSeparator "." +#define kVersionTag "Version" + + +enum UResEntryType { + ENTRY_OK = 0, + ENTRY_GOTO_ROOT = 1, + ENTRY_GOTO_DEFAULT = 2, + ENTRY_INVALID = 3 +}; + +typedef enum UResEntryType UResEntryType; + +struct UResourceDataEntry; +typedef struct UResourceDataEntry UResourceDataEntry; + +struct UResourceDataEntry { + char *fName; /* name of the locale for bundle - still to decide whether it is original or fallback */ + char *fPath; /* path to bundle - used for distinguishing between resources with the same name */ + uint32_t fCountExisting; /* how much is this resource used */ + ResourceData fData; /* data for low level access */ + UResourceDataEntry *fParent; /*next resource in fallback chain*/ + UResEntryType fStatus; + UErrorCode fBogus; + int32_t fHashKey; /* for faster access in the hashtable */ +}; + +struct UResourceBundle { + const char *fKey; /*tag*/ + char *fVersion; + bool_t fHasFallback; + bool_t fIsTopLevel; + bool_t fIsStackObject; + UResourceDataEntry *fData; /*for low-level access*/ + int32_t fIndex; + int32_t fSize; + ResourceData fResData; + Resource fRes; +}; + +/*U_CFUNC UResourceBundle* ures_openNoFallback(UResourceBundle *r, const char* path, const char* localeID, UErrorCode* status);*/ +U_CFUNC UResourceBundle* ures_openNoFallback(const char* path, const char* localeID, UErrorCode* status); +U_CFUNC const char* ures_getRealLocale(const UResourceBundle* resourceBundle, UErrorCode* status); +/*U_CFUNC UChar** ures_listInstalledLocales(const char *path, int32_t* count);*/ +U_CFUNC const ResourceData *getFallbackData(const UResourceBundle* resBundle, const char* * resTag, Resource *res, UErrorCode *status); +U_CFUNC int32_t hashBundle(const void *parm); +U_CFUNC bool_t compareBundles(const void *p1, const void *p2); + +/* Candidates for export */ +U_CFUNC UResourceBundle *copyResb(UResourceBundle *r, const UResourceBundle *original); +U_CFUNC void copyResbFillIn(UResourceBundle *dest, const UResourceBundle *original); +U_CFUNC const char* ures_getName(const UResourceBundle* resB); +U_CFUNC const char* ures_getPath(const UResourceBundle* resB); +U_CFUNC const char* ures_getTag(const UResourceBundle* resB); +U_CFUNC const ResourceData * ures_getResData(const UResourceBundle* resB); +/* +U_CAPI int32_t U_EXPORT2 ures_getStringArray(const UResourceBundle* resourceBundle, const char* resourceTag, const UChar** array, + int32_t maxLen, UErrorCode* err); + +U_CAPI int32_t U_EXPORT2 ures_get2dStringArray(const UResourceBundle* resourceBundle, const char* resourceTag, const UChar*** matrix, + int32_t maxRows, int32_t cols, UErrorCode* err); + +U_CAPI int32_t U_EXPORT2 ures_getTaggedStringArray(const UResourceBundle* resourceBundle, const char* resourceTag, const char** itemTags, + const UChar** items, int32_t maxItems, + UErrorCode* err); + +*/ +#endif /*URESIMP_H*/ diff --git a/icu4c/source/i18n/calendar.cpp b/icu4c/source/i18n/calendar.cpp index e9f5eb607b6..7e17423d1c5 100644 --- a/icu4c/source/i18n/calendar.cpp +++ b/icu4c/source/i18n/calendar.cpp @@ -702,11 +702,13 @@ Calendar::setWeekCountData(const Locale& desiredLocale, UErrorCode& status) // "1" // min days in week // } - const UnicodeString *dateTimeElements; - int32_t count; + //const UnicodeString *dateTimeElements; + //int32_t count; if (U_FAILURE(status)) return; - ResourceBundle resource(u_getDataDirectory(), desiredLocale, status); + ResourceBundle resource(NULL, desiredLocale, status); + //ResourceBundle resource(Locale::getDataDirectory(), desiredLocale, status); + //resource.open(UnicodeString(""), desiredLocale, status); // If the resource data doesn't seem to be present at all, then use last-resort // hard-coded data. @@ -718,16 +720,22 @@ Calendar::setWeekCountData(const Locale& desiredLocale, UErrorCode& status) return; } - dateTimeElements = resource.getStringArray(kDateTimeElements, count, status); + //dateTimeElements = resource.getStringArray(kDateTimeElements, count, status); + ResourceBundle dateTimeElements = resource.get(kDateTimeElements, status); + + if (U_FAILURE(status)) return; - if (count != 2) +// if (count != 2) + if(dateTimeElements.getSize()!=2) { status = U_INVALID_FORMAT_ERROR; return; } - fFirstDayOfWeek = (Calendar::EDaysOfWeek)stringToDayNumber(dateTimeElements[0], status); - fMinimalDaysInFirstWeek = (uint8_t)stringToDayNumber(dateTimeElements[1], status); + //fFirstDayOfWeek = (Calendar::EDaysOfWeek)stringToDayNumber(dateTimeElements[0], status); + //fMinimalDaysInFirstWeek = (uint8_t)stringToDayNumber(dateTimeElements[1], status); + fFirstDayOfWeek = (Calendar::EDaysOfWeek)stringToDayNumber(dateTimeElements.getStringEx((int32_t)0, status), status); + fMinimalDaysInFirstWeek = (uint8_t)stringToDayNumber(dateTimeElements.getStringEx(1, status), status); } /** diff --git a/icu4c/source/i18n/datefmt.cpp b/icu4c/source/i18n/datefmt.cpp index 3ceae9b218a..0c2b1c4fcfe 100644 --- a/icu4c/source/i18n/datefmt.cpp +++ b/icu4c/source/i18n/datefmt.cpp @@ -17,10 +17,10 @@ ******************************************************************************** */ +#include "unicode/resbund.h" #include "unicode/datefmt.h" #include "unicode/smpdtfmt.h" #include "mutex.h" -#include "unicode/resbund.h" // ***************************************************************************** // class DateFormat @@ -242,9 +242,12 @@ DateFormat::getAvailableLocales(int32_t& count) for (i=0; igetByKey(tag, status); + length = data.getSize(); + *field = new UnicodeString[length]; + for(int32_t i = 0; ifZoneStrings[i][j]); + s2 = fSymbols->fZoneStrings[i][j]; s2.toLower(); if ((s1.compare(start, s2.length(), s2, 0, s2.length())) == 0) diff --git a/icu4c/source/i18n/tblcoll.cpp b/icu4c/source/i18n/tblcoll.cpp index 68e5a109c88..fce86b4bd84 100644 --- a/icu4c/source/i18n/tblcoll.cpp +++ b/icu4c/source/i18n/tblcoll.cpp @@ -947,17 +947,19 @@ RuleBasedCollator::constructFromFile( const Locale& locale, char *binaryFilePath = createPathName(UnicodeString(u_getDataDirectory(),""), localeFileName, UnicodeString(kFilenameSuffix,"")); - if(tryBinaryFile) { - // Try to load up the collation from a binary file first - constructFromFile(binaryFilePath, status); -#ifdef COLLDEBUG - cerr << localeFileName << kFilenameSuffix << " binary load " << u_errorName(status) << endl; -#endif - if(U_SUCCESS(status) || status == U_MEMORY_ALLOCATION_ERROR) - { - delete [] binaryFilePath; - return; - } + if(tryBinaryFile) { + // Try to load up the collation from a binary file first + constructFromFile(binaryFilePath, status); + #ifdef COLLDEBUG + cerr << localeFileName << kFilenameSuffix << " binary load " << u_errorName(status) << endl; + #endif + if(U_SUCCESS(status) || status == U_MEMORY_ALLOCATION_ERROR) { + delete [] binaryFilePath; + return; + } + if(status == U_FILE_ACCESS_ERROR) { + status = U_ZERO_ERROR; + } } // Now try to load it up from a resource bundle text source file @@ -966,7 +968,6 @@ RuleBasedCollator::constructFromFile( const Locale& locale, char *ch; ch = new char[localeFileName.size() + 1]; ch[localeFileName.extract(0, 0x7fffffff, ch, "")] = 0; - ResourceBundle bundle(dataDir, ch, status); delete [] ch; @@ -978,21 +979,26 @@ RuleBasedCollator::constructFromFile( const Locale& locale, return; } -#ifdef COLLDEBUG - cerr << localeFileName << " ascii load " << u_errorName(status) << endl; -#endif + #ifdef COLLDEBUG + cerr << localeFileName << " ascii load " << u_errorName(status) << endl; + #endif - // check and see if this resource bundle contains collation data + // check and see if this resource bundle contains collation data - UnicodeString colString; - UErrorCode intStatus = U_ZERO_ERROR; + UnicodeString colString; + UErrorCode intStatus = U_ZERO_ERROR; +/* REDO */ + const UnicodeString *t = bundle.getString("CollationElements", intStatus); - bundle.getString("CollationElements", colString, intStatus); - if(colString.isBogus()) { - status = U_MEMORY_ALLOCATION_ERROR; - delete [] binaryFilePath; - return; - } + if(t != NULL) { + colString = *t; + } + + if(colString.isBogus()) { + status = U_MEMORY_ALLOCATION_ERROR; + delete [] binaryFilePath; + return; + } // if this bundle doesn't contain collation data, break out if(U_FAILURE(intStatus)) { diff --git a/icu4c/source/i18n/translit.cpp b/icu4c/source/i18n/translit.cpp index 9cf92c22f65..965be44025b 100644 --- a/icu4c/source/i18n/translit.cpp +++ b/icu4c/source/i18n/translit.cpp @@ -383,7 +383,9 @@ UnicodeString& Transliterator::getDisplayName(const UnicodeString& ID, const Locale& inLocale, UnicodeString& result) { UErrorCode status = U_ZERO_ERROR; + ResourceBundle bundle(u_getDataDirectory(), inLocale, status); + // Suspend checking status until later... // build the char* key @@ -394,10 +396,13 @@ UnicodeString& Transliterator::getDisplayName(const UnicodeString& ID, // Try to retrieve a UnicodeString* from the bundle. The result, // if any, should NOT be deleted. - const UnicodeString* resString = bundle.getString(key, status); + /*const UnicodeString* resString = bundle.getString(key, status);*/ + UnicodeString resString = bundle.getStringEx(key, status); - if (U_SUCCESS(status) && resString != 0) { - return result = *resString; // [sic] assign & return + /*if (U_SUCCESS(status) && resString != 0) {*/ + if (U_SUCCESS(status) && resString.length() != 0) { + /*return result = *resString; // [sic] assign & return*/ + return result = resString; // [sic] assign & return } // We have failed to get a name from the locale data. This is @@ -407,10 +412,13 @@ UnicodeString& Transliterator::getDisplayName(const UnicodeString& ID, // name from the ID. status = U_ZERO_ERROR; - resString = bundle.getString(RB_DISPLAY_NAME_PATTERN, status); + /*resString = bundle.getString(RB_DISPLAY_NAME_PATTERN, status);*/ + resString = bundle.getStringEx(RB_DISPLAY_NAME_PATTERN, status); - if (U_SUCCESS(status) && resString != 0) { - MessageFormat msg(*resString, inLocale, status); + /*if (U_SUCCESS(status) && resString != 0) {*/ + if (U_SUCCESS(status) && resString.length() != 0) { + /*MessageFormat msg(*resString, inLocale, status);*/ + MessageFormat msg(resString, inLocale, status); // Suspend checking status until later... // We pass either 2 or 3 Formattable objects to msg. @@ -440,10 +448,12 @@ UnicodeString& Transliterator::getDisplayName(const UnicodeString& ID, args[j].getString(s); key[length + s.extract(0, sizeof(key)-length-1, key+length, "")]=0; - resString = bundle.getString(key, status); + /*resString = bundle.getString(key, status);*/ + resString = bundle.getStringEx(key, status); if (U_SUCCESS(status)) { - args[j] = *resString; + /*args[j] = *resString;*/ + args[j] = resString; } } @@ -642,20 +652,22 @@ Transliterator* Transliterator::_createInstance(const UnicodeString& ID, // 2-d array at static init time, as a locale language. We're // just using the locale mechanism to map through to a file // name; this in no way represents an actual locale. + char *ch; ch = new char[entry->rbFile.size() + 1]; ch[entry->rbFile.extract(0, 0x7fffffff, ch, "")] = 0; Locale fakeLocale(ch); delete [] ch; - ResourceBundle bundle(Transliterator::getDataDirectory(), + ResourceBundle bundle(NULL, fakeLocale, status); // Call RBT to parse the rules from the resource bundle // We don't own the rules - 'rules' is an alias pointer to // a string in the RB cache. - const UnicodeString* rules = bundle.getString(RB_RULE, status); + /*const UnicodeString* rules = bundle.getString(RB_RULE, status);*/ + UnicodeString rules = bundle.getStringEx(RB_RULE, status); // If rules == 0 at this point, or if the status indicates a // failure, then we don't have any rules -- there is probably @@ -663,9 +675,15 @@ Transliterator* Transliterator::_createInstance(const UnicodeString& ID, // correspond to all the installed transliterators; if it // lists something that's not installed, we'll get a null // pointer here. - if (rules != 0 && U_SUCCESS(status)) { +/* if (rules != 0 && U_SUCCESS(status)) { data = TransliterationRuleParser::parse(*rules, isReverse + ? RuleBasedTransliterator::REVERSE + : RuleBasedTransliterator::FORWARD, + parseError); */ + if (rules.length() != 0 && U_SUCCESS(status)) { + + data = TransliterationRuleParser::parse(rules, isReverse ? RuleBasedTransliterator::REVERSE : RuleBasedTransliterator::FORWARD, parseError); @@ -868,9 +886,13 @@ void Transliterator::initializeCache(void) { * } */ - Locale indexLoc("index"); + Locale indexLoc("translit_index"); +/* ResourceBundle bundle(Transliterator::getDataDirectory(), indexLoc, status); +*/ + ResourceBundle bundle(NULL, + indexLoc, status); int32_t rows, cols; const UnicodeString** ruleBasedIDs = @@ -886,7 +908,7 @@ void Transliterator::initializeCache(void) { entry->entryType = (col == 0) ? CacheEntry::RULE_BASED_PLACEHOLDER : CacheEntry::REVERSE_RULE_BASED_PLACEHOLDER; - entry->rbFile = row[2]; + entry->rbFile = UnicodeString(row[2]); //uhash_putKey(cache, hash(row[col]), entry, &status); cache->put(row[col], entry, status); @@ -897,7 +919,8 @@ void Transliterator::initializeCache(void) { * need to do is change the id vector so that it * owns its strings and create a copy here. */ - cacheIDs.addElement((void*) &row[col]); + /*cacheIDs.addElement((void*) &row[col]);*/ + cacheIDs.addElement((void*) new UnicodeString(row[col])); } } } diff --git a/icu4c/source/i18n/unicode/dtfmtsym.h b/icu4c/source/i18n/unicode/dtfmtsym.h index 9209d77e617..0125e82e0e8 100644 --- a/icu4c/source/i18n/unicode/dtfmtsym.h +++ b/icu4c/source/i18n/unicode/dtfmtsym.h @@ -20,6 +20,7 @@ #include "unicode/utypes.h" #include "unicode/locid.h" +#include "unicode/resbund.h" /* forward declaration */ class SimpleDateFormat; @@ -298,6 +299,8 @@ private: static UnicodeString fgPatternChars; private: + + void initField(UnicodeString **field, int32_t& length, const ResourceBundle data, uint8_t ownfield, UErrorCode &status); /** * Called by the constructors to actually load data from the resources */ diff --git a/icu4c/source/test/cintltst/Makefile.in b/icu4c/source/test/cintltst/Makefile.in index 1a907dcdc88..0e07fbdf45a 100644 --- a/icu4c/source/test/cintltst/Makefile.in +++ b/icu4c/source/test/cintltst/Makefile.in @@ -66,7 +66,7 @@ OBJECTS = callcoll.o calltest.o capitst.o cbiapts.o cbkittst.o \ ccaltst.o ccapitst.o ccolltst.o cconvtst.o ccurrtst.o cdantst.o \ cdattst.o cdetst.o cdtdptst.o cdtrgtst.o cestst.o cfintst.o cformtst.o \ cfrtst.o cg7coll.o chashtst.o cintltst.o citertst.o cjaptst.o cloctst.o cmsgtst.o \ -cnmdptst.o cnormtst.o cnumtst.o cregrtst.o crestst.o cturtst.o \ +cnmdptst.o cnormtst.o cnumtst.o cregrtst.o crestst.o creststn.o cturtst.o \ cucdtst.o cutiltst.o encoll.o nucnvtst.o susctest.o nccbtst.o \ cbiditst.o cbididat.o eurocreg.o udatatst.o utf16tst.o diff --git a/icu4c/source/test/cintltst/cintltst.c b/icu4c/source/test/cintltst/cintltst.c index c09494047d9..9678db887fd 100644 --- a/icu4c/source/test/cintltst/cintltst.c +++ b/icu4c/source/test/cintltst/cintltst.c @@ -56,7 +56,7 @@ int main ( int argc, const char **argv ) return 1; } - rb = ures_open(0, "en", &errorCode); + rb = ures_open(NULL, "en", &errorCode); if(U_SUCCESS(errorCode)) { /* ok */ ures_close(rb); @@ -79,7 +79,7 @@ void ctest_pathnameInContext( char* fullname, int32_t maxsize, const char* relPath ) { char mainDirBuffer[200]; - char* mainDir; + char* mainDir = NULL; const char inpSepChar = '|'; char* tmp; int32_t lenMainDir; diff --git a/icu4c/source/test/cintltst/cintltst.dsp b/icu4c/source/test/cintltst/cintltst.dsp index 2187a3a4f7a..ecae9a56a13 100644 --- a/icu4c/source/test/cintltst/cintltst.dsp +++ b/icu4c/source/test/cintltst/cintltst.dsp @@ -75,6 +75,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 ..\..\..\lib\debug\icuuc.lib ..\..\..\lib\debug\icui18n.lib ..\..\..\lib\debug\ctestfw.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# SUBTRACT LINK32 /profile !ENDIF @@ -219,6 +220,10 @@ SOURCE=.\crestst.c # End Source File # Begin Source File +SOURCE=.\creststn.c +# End Source File +# Begin Source File + SOURCE=.\cturtst.c # End Source File # Begin Source File @@ -375,6 +380,10 @@ SOURCE=.\crestst.h # End Source File # Begin Source File +SOURCE=.\creststn.h +# End Source File +# Begin Source File + SOURCE=.\cturtst.h # End Source File # Begin Source File diff --git a/icu4c/source/test/cintltst/creststn.c b/icu4c/source/test/cintltst/creststn.c new file mode 100644 index 00000000000..577d83e9cbe --- /dev/null +++ b/icu4c/source/test/cintltst/creststn.c @@ -0,0 +1,790 @@ +/******************************************************************** + * COPYRIGHT: + * Copyright (c) 1997-1999, International Business Machines Corporation and + * others. All Rights Reserved. + ********************************************************************/ +/******************************************************************************** +* +* File CRESTST.C +* +* Modification History: +* Name Date Description +* Madhu Katragadda 05/09/2000 Ported Tests for New ResourceBundle API +********************************************************************************* +*/ + + +#include "unicode/utypes.h" +#include "cintltst.h" +#include "unicode/utypes.h" +#include "unicode/ustring.h" +#include "string.h" +#include "cstring.h" +#include + +#define RESTEST_HEAP_CHECK 0 + +#include "unicode/uloc.h" +#include "unicode/ures.h" +#include "creststn.h" +#include "unicode/ctest.h" +#include + +/*****************************************************************************/ +/** + * Return a random unsigned long l where 0N <= l <= ULONG_MAX. + */ + +static uint32_t +randul() +{ + uint32_t l; + int32_t i; + static bool_t initialized = FALSE; + if (!initialized) + { + srand((unsigned)time(NULL)); + initialized = TRUE; + } + // Assume rand has at least 12 bits of precision + + for (i=0; i> 4; + return l; +} + +/** + * Return a random double x where 0.0 <= x < 1.0. + */ +static double +randd() +{ + return ((double)randul()) / ULONG_MAX; +} + +/** + * Return a random integer i where 0 <= i < n. + */ +static int32_t randi(int32_t n) +{ + return (int32_t)(randd() * n); +} +//*************************************************************************************** +/** + * Convert an integer, positive or negative, to a character string radix 10. + */ +static char* +itoa1(int32_t i, char* buf) +{ + char *p = 0; + char* result = buf; + /* Handle negative */ + if(i < 0) { + *buf++ = '-'; + i = -i; + } + + /* Output digits in reverse order */ + p = buf; + do { + *p++ = '0' + (i % 10); + i /= 10; + } + while(i); + *p-- = 0; + + /* Reverse the string */ + while(buf < p) { + char c = *buf; + *buf++ = *p; + *p-- = c; + } + + return result; +} +static const int32_t kERROR_COUNT = -1234567; +static const UChar kERROR[] = { 0x0045 /*E*/, 0x0052 /*'R'*/, 0x0052 /*'R'*/, + 0x004F /*'O'*/, 0x0052/*'R'*/, 0x0000 /*'\0'*/}; + +/*****************************************************************************/ + +enum E_Where +{ + e_Root, + e_te, + e_te_IN, + e_Where_count +}; +typedef enum E_Where E_Where; +/*****************************************************************************/ + +#define CONFIRM_EQ(actual,expected) if (u_strcmp(expected,actual)==0){ record_pass(); } else { record_fail(); log_err("%s returned %s instead of %s\n", action, austrdup(actual), austrdup(expected)); pass=FALSE; } +#define CONFIRM_INT_EQ(actual,expected) if ((expected)==(actual)) { record_pass(); } else { record_fail(); log_err("%s returned %d instead of %d\n", action, actual, expected); pass=FALSE; } +#define CONFIRM_INT_GE(actual,expected) if ((actual)>=(expected)) { record_pass(); } else { record_fail(); log_err("%s returned %d instead of x >= %d\n", action, actual, expected); pass=FALSE; } +#define CONFIRM_INT_NE(actual,expected) if ((expected)!=(actual)) { record_pass(); } else { record_fail(); log_err("%s returned %d instead of x != %d\n", action, actual, expected); pass=FALSE; } +#define CONFIRM_ErrorCode(actual,expected) if ((expected)==(actual)) { record_pass(); } else { record_fail(); log_err("%s returned %s instead of %s\n", action, myErrorName(actual), myErrorName(expected)); pass=FALSE; } + + +/* Array of our test objects */ + +static struct +{ + const char* name; + UErrorCode expected_constructor_status; + E_Where where; + bool_t like[e_Where_count]; + bool_t inherits[e_Where_count]; +} +param[] = +{ + /* "te" means test */ + /* "IN" means inherits */ + /* "NE" or "ne" means "does not exist" */ + + { "root", U_ZERO_ERROR, e_Root, { TRUE, FALSE, FALSE }, { TRUE, FALSE, FALSE } }, + { "te", U_ZERO_ERROR, e_te, { FALSE, TRUE, FALSE }, { TRUE, TRUE, FALSE } }, + { "te_IN", U_ZERO_ERROR, e_te_IN, { FALSE, FALSE, TRUE }, { TRUE, TRUE, TRUE } }, + { "te_NE", U_USING_FALLBACK_ERROR, e_te, { FALSE, TRUE, FALSE }, { TRUE, TRUE, FALSE } }, + { "te_IN_NE", U_USING_FALLBACK_ERROR, e_te_IN, { FALSE, FALSE, TRUE }, { TRUE, TRUE, TRUE } }, + { "ne", U_USING_DEFAULT_ERROR, e_Root, { TRUE, FALSE, FALSE }, { TRUE, FALSE, FALSE } } +}; + +static int32_t bundles_count = sizeof(param) / sizeof(param[0]); + + +static void printUChars(UChar*); +/***************************************************************************************/ + +/* Array of our test objects */ + +void addNEWResourceBundleTest(TestNode** root) +{ + addTest(root, &TestConstruction1, "tsutil/creststn/TestConstruction1"); + addTest(root, &TestConstruction2, "tsutil/creststn/TestConstruction2"); + addTest(root, &TestResourceBundles, "tsutil/creststn/TestResourceBundle"); + addTest(root, &TestFallback, "tsutil/creststn/TestFallback"); + addTest(root, &TestAliasConflict, "tsutil/creststn/TestAlias"); + +} + + +/***************************************************************************************/ +void TestAliasConflict(void) { + UErrorCode status = U_ZERO_ERROR; + UResourceBundle *he = NULL; + UResourceBundle *iw = NULL; + const UChar *result = NULL; + + he = ures_open(NULL, "he", &status); + iw = ures_open(NULL, "iw", &status); + if(U_FAILURE(status)) { + log_err("Failed to get resource with %s", myErrorName(status)); + } + ures_close(iw); + result = ures_get(he, "ShortLanguage", &status); + if(U_FAILURE(status) || result == NULL) { + log_err("Failed to get resource with %s", myErrorName(status)); + } + ures_close(he); +} + + +void TestResourceBundles() +{ + + testTag("only_in_Root", TRUE, FALSE, FALSE); + testTag("in_Root_te", TRUE, TRUE, FALSE); + testTag("in_Root_te_te_IN", TRUE, TRUE, TRUE); + testTag("in_Root_te_IN", TRUE, FALSE, TRUE); + testTag("only_in_te", FALSE, TRUE, FALSE); + testTag("only_in_te_IN", FALSE, FALSE, TRUE); + testTag("in_te_te_IN", FALSE, TRUE, TRUE); + testTag("nonexistent", FALSE, FALSE, FALSE); + + log_verbose("Passed:= %d Failed= %d \n", pass, fail); + +} + + +void TestConstruction1() +{ + UResourceBundle *test1 = 0, *test2 = 0; + const UChar *result1, *result2; + UErrorCode status= U_ZERO_ERROR; + UErrorCode err = U_ZERO_ERROR; + const char* directory=NULL; + const char* locale="te_IN"; + char testdatapath[256]; + int32_t len1=0; + int32_t len2=0; + + U_STRING_DECL(rootVal, "ROOT", 4); + U_STRING_DECL(te_inVal, "TE_IN", 5); + + U_STRING_INIT(rootVal, "ROOT", 4); + U_STRING_INIT(te_inVal, "TE_IN", 5); + + + directory= ctest_getTestDirectory(); + uprv_strcpy(testdatapath, directory); + uprv_strcat(testdatapath, "testdata"); + log_verbose("Testing ures_open()......\n"); + + test1=ures_open(testdatapath, NULL, &err); + test2=ures_open(testdatapath, locale, &err); + + if(U_FAILURE(err)) + { + log_err("construction did not succeed : %s \n", myErrorName(status)); + return; + } + + result1= ures_getStringByKey(test1, "string_in_Root_te_te_IN", &len1, &err); + result2= ures_getStringByKey(test2, "string_in_Root_te_te_IN", &len2, &err); + if (U_FAILURE(err) || len1==0 || len2==0) { + log_err("Something threw an error in TestConstruction(): %s\n", myErrorName(status)); + return; + } + log_verbose("for string_in_Root_te_te_IN, default.txt had %s\n", austrdup(result1)); + log_verbose("for string_in_Root_te_te_IN, te_IN.txt had %s\n", austrdup(result2)); + if(u_strcmp(result1, rootVal) !=0 || u_strcmp(result2, te_inVal) !=0 ){ + log_err("construction test failed. Run Verbose for more information"); + } + + + /* Test getVersionNumber*/ + log_verbose("Testing version number\n"); + log_verbose("for getVersionNumber : %s\n", ures_getVersionNumber(test1)); + + ures_close(test1); + ures_close(test2); +} + +void TestConstruction2() +{ + + UChar temp[7]; + UResourceBundle *test4 = 0; + const UChar* result4; + UErrorCode err = U_ZERO_ERROR; + const char* directory; + const char* locale="te_IN"; + wchar_t widedirectory[256]; + char testdatapath[256]; + int32_t len=0; + + directory= ctest_getTestDirectory(); + uprv_strcpy(testdatapath, directory); + uprv_strcat(testdatapath, "testdata"); + mbstowcs(widedirectory, testdatapath, 256); + + log_verbose("Testing ures_openW().......\n"); + + test4=ures_openW(widedirectory, locale, &err); + if(U_FAILURE(err)){ + log_err("Error in the construction using ures_openW(): %s\n", myErrorName(err)); + return; + } + + result4=ures_getStringByKey(test4, "string_in_Root_te_te_IN", &len, &err); + if (U_FAILURE(err) || len==0) { + log_err("Something threw an error in TestConstruction() %s\n", myErrorName(err)); + return; + } + + log_verbose("for string_in_Root_te_te_IN, te_IN.txt had %s\n", austrdup(result4)); + u_uastrcpy(temp, "TE_IN"); + + if(u_strcmp(result4, temp)!=0) + { + + log_err("Construction test failed for ures_openW();\n"); + if(!VERBOSITY) + log_info("(run verbose for more information)\n"); + + log_verbose("\nGot->"); + printUChars((UChar*)result4); + log_verbose(" Want->"); + printUChars(temp); + log_verbose("\n"); + } + + + ures_close(test4); +} + +/*****************************************************************************/ +/*****************************************************************************/ + +bool_t testTag(const char* frag, + bool_t in_Root, + bool_t in_te, + bool_t in_te_IN) +{ + bool_t pass=TRUE; + + /* Make array from input params */ + + bool_t is_in[3]; + const char *NAME[] = { "ROOT", "TE", "TE_IN" }; + + /* Now try to load the desired items */ + UResourceBundle* theBundle = NULL; + char tag[99]; + char action[256]; + UErrorCode expected_status,status = U_ZERO_ERROR,expected_resource_status = U_ZERO_ERROR; + UChar* base = NULL; + UChar* expected_string = NULL; + const UChar* string = NULL; + char buf[5]; + char item_tag[10]; + int32_t i,j,row,col, len; + int32_t actual_bundle; + int32_t count = 0; + int32_t row_count=0; + int32_t column_count=0; + int32_t index = 0; + int32_t tag_count= 0; + char testdatapath[256]; + UResourceBundle* array=NULL; + UResourceBundle* array2d=NULL; + UResourceBundle* tags=NULL; + UResourceBundle* arrayItem1=NULL; + + const char* directory = ctest_getTestDirectory(); + + uprv_strcpy(testdatapath, directory); + uprv_strcat(testdatapath, "testdata"); + + is_in[0] = in_Root; + is_in[1] = in_te; + is_in[2] = in_te_IN; + + strcpy(item_tag, "tag"); + + for (i=0; i default */ + else if(i == 3) + actual_bundle = 1; /* te_NE -> te */ + else if(i == 4) + actual_bundle = 2; /* te_IN_NE -> te_IN */ + else + actual_bundle = i; + + expected_resource_status = U_MISSING_RESOURCE_ERROR; + for (j=e_te_IN; j>=e_Root; --j) + { + if (is_in[j] && param[i].inherits[j]) + { + + if(j == actual_bundle) /* it's in the same bundle OR it's a nonexistent=default bundle (5) */ + expected_resource_status = U_ZERO_ERROR; + else if(j == 0) + expected_resource_status = U_USING_DEFAULT_ERROR; + else + expected_resource_status = U_USING_FALLBACK_ERROR; + + log_verbose("%s[%d]::%s: in<%d:%s> inherits<%d:%s>. actual_bundle=%s\n", + param[i].name, + i, + frag, + j, + is_in[j]?"Yes":"No", + j, + param[i].inherits[j]?"Yes":"No", + param[actual_bundle].name); + + break; + } + } + + for (j=param[i].where; j>=0; --j) + { + if (is_in[j]) + { + base=(UChar*)malloc(sizeof(UChar)*(strlen(NAME[j]) + 1)); + u_uastrcpy(base,NAME[j]); + + break; + } + else { + base = (UChar*) malloc(sizeof(UChar) * 1); + *base = 0x0000; + } + } + + /*----string---------------------------------------------------------------- */ + + strcpy(tag,"string_"); + strcat(tag,frag); + + strcpy(action,param[i].name); + strcat(action, ".ures_getStringByKey(" ); + strcat(action,tag); + strcat(action, ")"); + + + status = U_ZERO_ERROR; + len=0; + + string=ures_getStringByKey(theBundle, tag, &len, &status); + if(U_SUCCESS(status)) { + expected_string=(UChar*)malloc(sizeof(UChar)*(u_strlen(base) + 4)); + u_strcpy(expected_string,base); + CONFIRM_INT_EQ(len, u_strlen(expected_string)); + }else{ + expected_string = (UChar*)malloc(sizeof(UChar)*(u_strlen(kERROR) + 1)); + u_strcpy(expected_string,kERROR); + string=kERROR; + } + log_verbose("%s got %d, expected %d\n", action, status, expected_resource_status); + + CONFIRM_ErrorCode(status, expected_resource_status); + CONFIRM_EQ(string, expected_string); + + + + /*--------------array------------------------------------------------- */ + + strcpy(tag,"array_"); + strcat(tag,frag); + + strcpy(action,param[i].name); + strcat(action, ".ures_getByKey(" ); + strcat(action,tag); + strcat(action, ")"); + + len=0; + + count = kERROR_COUNT; + status = U_ZERO_ERROR; + array=ures_getByKey(theBundle, tag, array, &status); + CONFIRM_ErrorCode(status,expected_resource_status); + if (U_SUCCESS(status)) { + //confirm the resource type is an array + CONFIRM_INT_EQ(ures_getType(array), RES_ARRAY); + //confirm the size + count=ures_getSize(array); + CONFIRM_INT_GE(count,1); + for (j=0; j= 0 && index < count) ? expected_resource_status : U_MISSING_RESOURCE_ERROR; + CONFIRM_ErrorCode(status,expected_status); + CONFIRM_EQ(string,expected_string); + + } + + + /*--------------2dArray------------------------------------------------- */ + + strcpy(tag,"array_2d_"); + strcat(tag,frag); + + strcpy(action,param[i].name); + strcat(action, ".ures_getByKey(" ); + strcat(action,tag); + strcat(action, ")"); + + + + row_count = kERROR_COUNT, column_count = kERROR_COUNT; + status = U_ZERO_ERROR; + array2d=ures_getByKey(theBundle, tag, array2d, &status); + + CONFIRM_ErrorCode(status,expected_resource_status); + if (U_SUCCESS(status)) + { + //confirm the resource type is an 2darray + CONFIRM_INT_EQ(ures_getType(array2d), RES_ARRAY); + row_count=ures_getSize(array2d); + CONFIRM_INT_GE(row_count,1); + + for(row=0; row= 0 && row < row_count && col >= 0 && col < column_count) ? + expected_resource_status: U_MISSING_RESOURCE_ERROR; + CONFIRM_ErrorCode(status,expected_status); + + if (U_SUCCESS(status)){ + UChar element[3]; + u_strcpy(expected_string, base); + u_uastrcpy(element, itoa1(row, buf)); + u_strcat(expected_string, element); + u_uastrcpy(element, itoa1(col, buf)); + u_strcat(expected_string, element); + } else { + u_strcpy(expected_string,kERROR); + } + CONFIRM_EQ(string,expected_string); + + } + + /*--------------taggedArray----------------------------------------------- */ + strcpy(tag,"tagged_array_"); + strcat(tag,frag); + + strcpy(action,param[i].name); + strcat(action,".ures_getByKey("); + strcat(action, tag); + strcat(action,")"); + + + status = U_ZERO_ERROR; + tag_count=0; + tags=ures_getByKey(theBundle, tag, tags, &status); + CONFIRM_ErrorCode(status, expected_resource_status); + if (U_SUCCESS(status)) { + UResType bundleType=ures_getType(tags); + CONFIRM_INT_EQ(bundleType, RES_TABLE); + + tag_count=ures_getSize(tags); + CONFIRM_INT_GE((int32_t)tag_count, (int32_t)0); + + for(index=0; index +#include +#include + +#define RESTEST_HEAP_CHECK 0 + +#include "unicode/utypes.h" + +#if defined(_WIN32) && !defined(__WINDOWS__) +#define _CRTDBG_MAP_ALLOC +#include +#endif + +#include "cstring.h" +#include "unicode/unistr.h" +#include "unicode/resbund.h" +#include "restsnew.h" + +//*************************************************************************************** + +static const UnicodeString kERROR = UNICODE_STRING("ERROR", 5); +static const UChar kErrorUChars[] = { 0x45, 0x52, 0x52, 0x4f, 0x52, 0 }; +static const kErrorLength = 5; +static const int32_t kERROR_COUNT = -1234567; + +//*************************************************************************************** + +enum E_Where +{ + e_Root, + e_te, + e_te_IN, + e_Where_count +}; + +//*************************************************************************************** + +#define CONFIRM_EQ(actual,expected) if ((expected)==(actual)) { record_pass(); } else { record_fail(); OUT << action << " returned " << (actual) << " instead of " << (expected) << endl; pass=FALSE; } +#define CONFIRM_GE(actual,expected) if ((actual)>=(expected)) { record_pass(); } else { record_fail(); OUT << action << " returned " << (actual) << " instead of x >= " << (expected) << endl; pass=FALSE; } +#define CONFIRM_NE(actual,expected) if ((expected)!=(actual)) { record_pass(); } else { record_fail(); OUT << action << " returned " << (actual) << " instead of x != " << (expected) << endl; pass=FALSE; } + +#define CONFIRM_UErrorCode(actual,expected) if ((expected)==(actual)) { record_pass(); } else { record_fail(); OUT << action << " returned " << u_errorName(actual) << " instead of " << u_errorName(expected) << endl; pass=FALSE; } + +//*************************************************************************************** + +/** + * Convert an integer, positive or negative, to a character string radix 10. + */ +static char* +itoa(int32_t i, char* buf) +{ + char* result = buf; + + // Handle negative + if (i < 0) + { + *buf++ = '-'; + i = -i; + } + + // Output digits in reverse order + char* p = buf; + do + { + *p++ = '0' + (i % 10); + i /= 10; + } + while (i); + *p-- = 0; + + // Reverse the string + while (buf < p) + { + char c = *buf; + *buf++ = *p; + *p-- = c; + } + + return result; +} + + + +//*************************************************************************************** + +// Array of our test objects + +static struct +{ + const char* name; + Locale *locale; + UErrorCode expected_constructor_status; + E_Where where; + bool_t like[e_Where_count]; + bool_t inherits[e_Where_count]; +} +param[] = +{ + // "te" means test + // "IN" means inherits + // "NE" or "ne" means "does not exist" + + { "root", 0, U_ZERO_ERROR, e_Root, { TRUE, FALSE, FALSE }, { TRUE, FALSE, FALSE } }, + { "te", 0, U_ZERO_ERROR, e_te, { FALSE, TRUE, FALSE }, { TRUE, TRUE, FALSE } }, + { "te_IN", 0, U_ZERO_ERROR, e_te_IN, { FALSE, FALSE, TRUE }, { TRUE, TRUE, TRUE } }, + { "te_NE", 0, U_USING_FALLBACK_ERROR, e_te, { FALSE, TRUE, FALSE }, { TRUE, TRUE, FALSE } }, + { "te_IN_NE", 0, U_USING_FALLBACK_ERROR, e_te_IN, { FALSE, FALSE, TRUE }, { TRUE, TRUE, TRUE } }, + { "ne", 0, U_USING_DEFAULT_ERROR, e_Root, { TRUE, FALSE, FALSE }, { TRUE, FALSE, FALSE } } +}; + +static int32_t bundles_count = sizeof(param) / sizeof(param[0]); + +//*************************************************************************************** + +/** + * Return a random unsigned long l where 0N <= l <= ULONG_MAX. + */ + +static uint32_t +randul() +{ + static bool_t initialized = FALSE; + if (!initialized) + { + srand((unsigned)time(NULL)); + initialized = TRUE; + } + // Assume rand has at least 12 bits of precision + uint32_t l; + for (int32_t i=0; i> 4; + return l; +} + +/** + * Return a random double x where 0.0 <= x < 1.0. + */ +static double +randd() +{ + return ((double)randul()) / ULONG_MAX; +} + +/** + * Return a random integer i where 0 <= i < n. + */ +static int32_t randi(int32_t n) +{ + return (int32_t)(randd() * n); +} + +//*************************************************************************************** + +NewResourceBundleTest::NewResourceBundleTest() +: pass(0), + fail(0), + OUT(it_out) +{ + param[0].locale = new Locale("root"); + param[1].locale = new Locale("te"); + param[2].locale = new Locale("te", "IN"); + param[3].locale = new Locale("te", "NE"); + param[4].locale = new Locale("te", "IN", "NE"); + param[5].locale = new Locale("ne"); +} + +NewResourceBundleTest::~NewResourceBundleTest() +{ +} + +void NewResourceBundleTest::runIndexedTest( int32_t index, bool_t exec, char* &name, char* par ) +{ + if (exec) logln("TestSuite ResourceBundleTest: "); + switch (index) { + case 0: name = "TestResourceBundles"; if (exec) TestResourceBundles(); break; + case 1: name = "TestConstruction"; if (exec) TestConstruction(); break; + case 2: name = "TestIteration"; if (exec) TestIteration(); break; + + default: name = ""; break; //needed to end loop + } +} + +//*************************************************************************************** + +void +NewResourceBundleTest::TestResourceBundles() +{ +#if defined(_WIN32) && !defined(__WINDOWS__) +#if defined(_DEBUG) && RESTEST_HEAP_CHECK + /* + * Set the debug-heap flag to keep freed blocks in the + * heap's linked list - This will allow us to catch any + * inadvertent use of freed memory + */ + int tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + tmpDbgFlag |= _CRTDBG_DELAY_FREE_MEM_DF; + tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF; + tmpDbgFlag |= _CRTDBG_CHECK_ALWAYS_DF; + _CrtSetDbgFlag(tmpDbgFlag); + + _CrtMemState memstate; + _CrtMemCheckpoint(&memstate); + { +#endif +#endif + + testTag("only_in_Root", TRUE, FALSE, FALSE); + testTag("only_in_te", FALSE, TRUE, FALSE); + testTag("only_in_te_IN", FALSE, FALSE, TRUE); + testTag("in_Root_te", TRUE, TRUE, FALSE); + testTag("in_Root_te_te_IN", TRUE, TRUE, TRUE); + testTag("in_Root_te_IN", TRUE, FALSE, TRUE); + testTag("in_te_te_IN", FALSE, TRUE, TRUE); + testTag("nonexistent", FALSE, FALSE, FALSE); + OUT << "Passed: " << pass << "\nFailed: " << fail << endl; + +#if defined(_WIN32) && !defined(__WINDOWS__) +#if defined(_DEBUG) && RESTEST_HEAP_CHECK + } + _CrtMemDumpAllObjectsSince(&memstate); + + /* + * Set the debug-heap flag to keep freed blocks in the + * heap's linked list - This will allow us to catch any + * inadvertent use of freed memory + */ + tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + tmpDbgFlag |= _CRTDBG_DELAY_FREE_MEM_DF; + tmpDbgFlag &= ~_CRTDBG_LEAK_CHECK_DF; + tmpDbgFlag &= ~_CRTDBG_CHECK_ALWAYS_DF; + _CrtSetDbgFlag(tmpDbgFlag); +#endif +#endif +} + +void +NewResourceBundleTest::TestConstruction() +{ + { + UErrorCode err = U_ZERO_ERROR; + const char *directory; + char testdatapath[256]; + Locale locale("te", "IN"); + + directory=IntlTest::getTestDirectory(); + uprv_strcpy(testdatapath, directory); + uprv_strcat(testdatapath, "testdata"); + + ResourceBundle test1(testdatapath, err); + ResourceBundle test2(testdatapath, locale, err); + + UnicodeString result1; + UnicodeString result2; + + result1 = test1.getStringEx("string_in_Root_te_te_IN", err); + result2 = test2.getStringEx("string_in_Root_te_te_IN", err); + if (U_FAILURE(err)) { + errln("Something threw an error in TestConstruction()"); + return; + } + + logln("for string_in_Root_te_te_IN, root.txt had " + result1); + logln("for string_in_Root_te_te_IN, te_IN.txt had " + result2); + + if (result1 != "ROOT" || result2 != "TE_IN") + errln("Construction test failed; run verbose for more information"); + + const char* version1; + const char* version2; + + version1 = test1.getVersionNumber(); + version2 = test2.getVersionNumber(); + + char *versionID1 = new char[1 + strlen(U_ICU_VERSION) + strlen(version1)]; // + 1 for zero byte + char *versionID2 = new char[1 + strlen(U_ICU_VERSION) + strlen(version2)]; // + 1 for zero byte + + strcpy(versionID1, U_ICU_VERSION); + strcat(versionID1, ".44"); // hardcoded, please change if the default.txt file or ResourceBundle::kVersionSeparater is changed. + + strcpy(versionID2, U_ICU_VERSION); + strcat(versionID2, ".55"); // hardcoded, please change if the te_IN.txt file or ResourceBundle::kVersionSeparater is changed. + + logln(UnicodeString("getVersionNumber on default.txt returned ") + version1); + logln(UnicodeString("getVersionNumber on te_IN.txt returned ") + version2); + + if (strcmp(version1, versionID1) != 0 || strcmp(version2, versionID2) != 0) + errln("getVersionNumber() failed"); + } + { + UErrorCode err = U_ZERO_ERROR; + const char *directory; + char testdatapath[256]; + Locale locale("te", "IN"); + + directory=IntlTest::getTestDirectory(); + uprv_strcpy(testdatapath, directory); + uprv_strcat(testdatapath, "testdata"); + + + wchar_t* wideDirectory = new wchar_t[256]; + mbstowcs(wideDirectory, testdatapath, 256); + + ResourceBundle test2(wideDirectory, locale, err); + + UnicodeString result2; + + result2 = test2.getStringEx("string_in_Root_te_te_IN", err); + if (U_FAILURE(err)) { + errln("Something threw an error in TestConstruction()"); + return; + } + + logln("for string_in_Root_te_te_IN, te_IN.txt had " + result2); + + if (result2 != "TE_IN") + errln("Construction test failed; run verbose for more information"); + } +} +void +NewResourceBundleTest::TestIteration() +{ + UErrorCode err = U_ZERO_ERROR; + const char *directory; + char testdatapath[256]; + const char* data[]={ + "string_in_Root_te_te_IN", "1", + "array_in_Root_te_te_IN", "5", + "array_2d_in_Root_te_te_IN", "4", + }; + + Locale *locale=new Locale("te_IN"); + + directory=IntlTest::getTestDirectory(); + uprv_strcpy(testdatapath, directory); + uprv_strcat(testdatapath, "testdata"); + + ResourceBundle test1(testdatapath, *locale, err); + if(U_FAILURE(err)){ + errln("Construction failed"); + } + int32_t i, count, row=0, col=0; + char buf[5]; + UnicodeString expected; + UnicodeString element("TE_IN"); + UnicodeString action; + + + for(i=0; i 1){ + CONFIRM_EQ(bundle.getType(), RES_ARRAY); + expected+=itoa(row, buf); + ResourceBundle rowbundle=bundle.get(row, err); + if(!U_FAILURE(err) && rowbundle.getSize()>1){ + col=0; + while(rowbundle.hasNext()){ + expected=element; + got=rowbundle.getNextString(err); + if(!U_FAILURE(err)){ + expected+=itoa(row, buf); + expected+=itoa(col, buf); + col++; + CONFIRM_EQ(got, expected); + } + } + CONFIRM_EQ(col, rowbundle.getSize()); + } + } + else{ + CONFIRM_EQ(bundle.getType(), RES_STRING); + } + } + CONFIRM_EQ(got, expected); + count++; + } + action = data[i]; + action +=".getSize()"; + CONFIRM_EQ(bundle.getSize(), count); + CONFIRM_EQ(count, atoi(data[i+1])); + //after reaching the end + err=U_ZERO_ERROR; + ResourceBundle errbundle=bundle.getNext(err); + action = "After reaching the end of the Iterator:- "; + action +=data[i]; + action +=".getNext()"; + CONFIRM_NE(err, U_ZERO_ERROR); + CONFIRM_EQ(u_errorName(err), u_errorName(U_INDEX_OUTOFBOUNDS_ERROR)); + //reset the iterator + err = U_ZERO_ERROR; + bundle.resetIterator(); + /* The following code is causing a crash + ****CRASH****** + */ + + bundle.getNext(err); + if(U_FAILURE(err)){ + errln("ERROR: getNext() throw an error"); + }/**/ + + + } + + + + } +} + + + + + + + + +//*************************************************************************************** + +bool_t +NewResourceBundleTest::testTag(const char* frag, + bool_t in_Root, + bool_t in_te, + bool_t in_te_IN) +{ + bool_t pass=TRUE; + + // Make array from input params + + bool_t is_in[] = { in_Root, in_te, in_te_IN }; + + const char* NAME[] = { "ROOT", "TE", "TE_IN" }; + + // Now try to load the desired items + + char tag[100]; + UnicodeString action; + + int32_t i,j,row,col, actual_bundle; + int32_t index; + const char *directory; + char testdatapath[256]; + + directory=IntlTest::getTestDirectory(); + uprv_strcpy(testdatapath, directory); + uprv_strcat(testdatapath, "testdata"); + + for (i=0; i default */ + else if(i == 3) + actual_bundle = 1; /* te_NE -> te */ + else if(i == 4) + actual_bundle = 2; /* te_IN_NE -> te_IN */ + else + actual_bundle = i; + + + UErrorCode expected_resource_status = U_MISSING_RESOURCE_ERROR; + for (j=e_te_IN; j>=e_Root; --j) + { + if (is_in[j] && param[i].inherits[j]) + { + if(j == actual_bundle) /* it's in the same bundle OR it's a nonexistent=default bundle (5) */ + expected_resource_status = U_ZERO_ERROR; + else if(j == 0) + expected_resource_status = U_USING_DEFAULT_ERROR; + else + expected_resource_status = U_USING_FALLBACK_ERROR; + + break; + } + } + + UErrorCode expected_status; + + UnicodeString base; + for (j=param[i].where; j>=0; --j) + { + if (is_in[j]) + { + base = NAME[j]; + break; + } + } + + //-------------------------------------------------------------------------- + // string + + uprv_strcpy(tag, "string_"); + uprv_strcat(tag, frag); + + action = param[i].name; + action += ".getStringEx("; + action += tag; + action += ")"; + + + status = U_ZERO_ERROR; + UnicodeString string = theBundle.getStringEx(tag, status); + if(U_FAILURE(status)) { + string.setTo(TRUE, kErrorUChars, kErrorLength); + } + + CONFIRM_UErrorCode(status, expected_resource_status); + + UnicodeString expected_string; + expected_string = U_SUCCESS(status) ? base : kERROR; + + CONFIRM_EQ(string, expected_string); + + //-------------------------------------------------------------------------- + // array ResourceBundle using the key + + uprv_strcpy(tag, "array_"); + uprv_strcat(tag, frag); + + action = param[i].name; + action += ".get("; + action += tag; + action += ")"; + + int32_t count = kERROR_COUNT; + status = U_ZERO_ERROR; + ResourceBundle array = theBundle.get(tag, status); + CONFIRM_UErrorCode(status,expected_resource_status); + + + if (U_SUCCESS(status)) + { + //confirm the resource type is an array + UResType bundleType=array.getType(); + CONFIRM_EQ(bundleType, RES_ARRAY); + + count=array.getSize(); + CONFIRM_GE(count,1); + + for (j=0; j= 0 && index < count) ? expected_resource_status : U_MISSING_RESOURCE_ERROR; + CONFIRM_UErrorCode(status,expected_status); + + if (U_SUCCESS(status)){ + char buf[32]; + expected_string = base; + expected_string += itoa(index,buf); + } else { + expected_string = kERROR; + } + CONFIRM_EQ(string,expected_string); + + } + + //-------------------------------------------------------------------------- + // 2dArray + + uprv_strcpy(tag, "array_2d_"); + uprv_strcat(tag, frag); + + action = param[i].name; + action += ".get("; + action += tag; + action += ")"; + + + int32_t row_count = kERROR_COUNT, column_count = kERROR_COUNT; + status = U_ZERO_ERROR; + ResourceBundle array2d=theBundle.get(tag, status); + + //const UnicodeString** array2d = theBundle.get2dArray(tag, row_count, column_count, status); + CONFIRM_UErrorCode(status,expected_resource_status); + + if (U_SUCCESS(status)) + { + //confirm the resource type is an 2darray + UResType bundleType=array2d.getType(); + CONFIRM_EQ(bundleType, RES_ARRAY); + + row_count=array2d.getSize(); + CONFIRM_GE(row_count,1); + + for(row=0; row= 0 && row < row_count && col >= 0 && col < column_count) ? + expected_resource_status: U_MISSING_RESOURCE_ERROR; + CONFIRM_UErrorCode(status,expected_status); + + if (U_SUCCESS(status)){ + char buf[32]; + expected_string = base; + expected_string += itoa(row,buf); + expected_string += itoa(col,buf); + } else { + expected_string = kERROR; + } + CONFIRM_EQ(string,expected_string); + + } + + //-------------------------------------------------------------------------- + // taggedArray + + uprv_strcpy(tag, "tagged_array_"); + uprv_strcat(tag, frag); + + action = param[i].name; + action += ".get("; + action += tag; + action += ")"; + + int32_t tag_count; + status = U_ZERO_ERROR; + + ResourceBundle tags=theBundle.get(tag, status); + CONFIRM_UErrorCode(status, expected_resource_status); + + if (U_SUCCESS(status)) { + UResType bundleType=tags.getType(); + CONFIRM_EQ(bundleType, RES_TABLE); + + tag_count=tags.getSize(); + CONFIRM_GE((int32_t)tag_count, (int32_t)0); + + for(index=0; index uprv_strlen("-e")) { - encoding = arg+2; - } else { - encoding = 0; - } - - } - else if(uprv_strncmp(arg, "-D", 2) == 0) { - outputDir = arg+2; - } - - /* POSIX.1 says all arguments after -- are not options */ - else if(uprv_strcmp(arg, "--") == 0) { - /* skip the -- */ - ++optind; - break; - } - /* unrecognized option */ - else if(uprv_strncmp(arg, "-", uprv_strlen("-")) == 0) { - printf("genrb: invalid option -- %s\n", arg+1); - printUsage = 1; - } - /* done with options, start file processing */ - else { - break; - } + /* error handling, printing usage message */ + if(argc<0) { + fprintf(stderr, "error in command line argument \"%s\"\n", argv[-argc]); + } else if(argc<2) { + argc=-1; } - /* print usage info */ - if(printUsage) { - usage(); - return 0; + if(argc<0 || options[HELP1].doesOccur || options[HELP2].doesOccur) { + fprintf(stderr, + "Usage: %s [OPTIONS] [FILES]\n" + "\treads the list of resource bundle source files and creates\n" + "\tbinary version of reosurce bundles (.res files)\n" + "\tOptions:\n" + "\t\t-h, -? or --help this usage text\n" + "\t\t-V or --version prints out version number and exits\n" + "\t\t-d of --destdir destination directory, followed by the path, defaults to %s\n" + "\t\t-v or --verbose be verbose\n" + "\t\t-e or --encoding encoding of source files, leave empty for system default encoding\n" + "\t\t NOTE: ICU must be completely built to use this option\n" + "\t\t-s or --sourcedir source directory for files followed by path, defaults to %s\n", + argv[0], u_getDataDirectory(), u_getDataDirectory()); + return argc<0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR; } - /* print version info */ - if(printVersion) { - version(); - return 0; + if(options[VERSION].doesOccur) { + fprintf(stderr, + "%s version %s (ICU version %s).\n" + "%s\n", + argv[0], GENRB_VERSION, U_ICU_VERSION, U_COPYRIGHT_STRING); + return U_ZERO_ERROR; + } + + if(options[VERBOSE].doesOccur) { + verbose = TRUE; + } + + if(options[SOURCEDIR].doesOccur) { + inputDir = options[SOURCEDIR].value; + } + + if(options[DESTDIR].doesOccur) { + outputDir = options[DESTDIR].value; + } + + if(options[ENCODING].doesOccur) { + encoding = options[ENCODING].value; } /* generate the binary files */ - for(i = optind; i < argc; ++i) { + for(i = 1; i < argc; ++i) { status = U_ZERO_ERROR; arg = getLongPathname(argv[i]); - processFile(arg, encoding, outputDir, &status); - make_col(arg, &status); +/* + if(outputDir == NULL) { + char *pathSepPosition = NULL; + pathSepPosition = uprv_strrchr(arg, U_FILE_SEP_CHAR); + if(pathSepPosition != NULL) { + int32_t pathLen = pathSepPosition-arg+1; + outputDir = (char *) uprv_malloc(sizeof(char)*(pathLen+1)); + uprv_strncpy(outputDir, arg, pathLen); + outputDir[pathLen] = '\0'; + } + } +*/ + printf("genrb: processing file \"%s\"\n", arg); + processFile(arg, encoding, inputDir, outputDir, &status); + /*make_col(arg, &status);*/ if(U_FAILURE(status)) { - printf("genrb: %s processing file \"%s\"\n", u_errorName(status), arg); - if(getErrorText() != 0) - printf(" (%s)\n", getErrorText()); + printf("genrb: %s processing file \"%s\"\n", u_errorName(status), arg); + if(getErrorText() != 0) + printf(" (%s)\n", getErrorText()); } } - return 0; -} - -/* Usage information */ -static void -usage() -{ - puts("Usage: genrb [OPTIONS] [FILES]"); - puts("Options:"); - puts(" -e Resource bundle is encoded with system default encoding"); - puts(" -eEncoding Resource bundle uses specified Encoding"); - puts(" -h, --help Print this message and exit."); - puts(" -v, --version Print the version number of genrb and exit."); - puts(" -Ddir Store ALL output files under 'dir'."); - encoding!=NULL?puts(encoding):puts("encoding is NULL"); -} - -/* Version information */ -static void -version() -{ - printf("genrb version %s (ICU version %s).\n", - GENRB_VERSION, U_ICU_VERSION); - puts(U_COPYRIGHT_STRING); + return status; } /* Process a file */ static void -processFile(const char *filename, const char *cp, const char *outputDir, - UErrorCode *status) +processFile(const char *filename, const char *cp, const char *inputDir, const char *outputDir, UErrorCode *status) { FileStream *in; - FileStream *rb_out; - struct SRBItemList *data; + struct SRBRoot *data; char *rbname; if(U_FAILURE(*status)) return; /* Setup */ - in = rb_out = 0; + in = 0; /* Open the input file for reading */ - in = T_FileStream_open(filename, "r"); + if(inputDir == NULL) { + in = T_FileStream_open(filename, "r"); + } else { + char *openFileName = NULL; + int32_t dirlen = uprv_strlen(inputDir); + int32_t filelen = uprv_strlen(filename); + if(inputDir[dirlen-1] != U_FILE_SEP_CHAR) { + openFileName = (char *) uprv_malloc(dirlen+filelen+2); + uprv_strcpy(openFileName, inputDir); + openFileName[dirlen] = U_FILE_SEP_CHAR; + openFileName[dirlen+1] = '\0'; + uprv_strcat(openFileName, filename); + } else { + openFileName = (char *) uprv_malloc(dirlen+filelen+1); + uprv_strcpy(openFileName, inputDir); + uprv_strcat(openFileName, filename); + } + in = T_FileStream_open(openFileName, "r"); + uprv_free(openFileName); + } + if(in == 0) { *status = U_FILE_ACCESS_ERROR; setErrorText("File not found"); return; } - /* Parse the data into an SRBItemList */ + /* Parse the data into an SRBRoot */ data = parse(in, cp, status); /* Determine the target rb filename */ @@ -199,22 +221,17 @@ processFile(const char *filename, const char *cp, const char *outputDir, } /* Open the target file for writing */ - rb_out = T_FileStream_open(rbname, "wb"); - if(rb_out == 0 || T_FileStream_error(rb_out) != 0) { - *status = U_FILE_ACCESS_ERROR; - setErrorText("Could not open file for writing"); - goto finish; - } - /* Write the data to the file */ - rb_write(rb_out, data, status); + /*rb_write(rb_out, data, status);*/ + bundle_write(data, outputDir, status); + /*bundle_write(data, outputDir, rbname, status);*/ + bundle_close(data, status); + finish: /* Clean up */ - rblist_close(data, status); T_FileStream_close(in); - T_FileStream_close(rb_out); uprv_free(rbname); } @@ -261,22 +278,29 @@ make_res_filename(const char *filename, } uprv_strcpy(resName, dirname); uprv_strcat(resName, basename); - uprv_strcat(resName, RES_SUFFIX); + /*uprv_strcat(resName, RES_SUFFIX);*/ } else { - /* output in 'outputDir' */ - resName = (char*) uprv_malloc(sizeof(char) * (uprv_strlen(outputDir) - + uprv_strlen(basename) - + uprv_strlen(RES_SUFFIX) + 1)); + int32_t dirlen = uprv_strlen(outputDir); + int32_t dirnamelen = uprv_strlen(dirname); + int32_t basenamelen = uprv_strlen(basename); + resName = (char*) uprv_malloc(sizeof(char) * (dirlen + basenamelen + 2)); + /*resName = (char*) uprv_malloc(sizeof(char) * (dirnamelen + basenamelen + 1));*/ if(resName == 0) { *status = U_MEMORY_ALLOCATION_ERROR; goto finish; } + uprv_strcpy(resName, outputDir); - uprv_strcat(resName, basename); - uprv_strcat(resName, RES_SUFFIX); - + + if(outputDir[dirlen] != U_FILE_SEP_CHAR) { + resName[dirlen] = U_FILE_SEP_CHAR; + resName[dirlen+1] = '\0'; + } + /*uprv_strcat(resName, dirname);*/ + /*uprv_strcpy(resName, dirname);*/ + uprv_strcat(resName, basename); } finish: diff --git a/icu4c/source/tools/genrb/genrb.dsp b/icu4c/source/tools/genrb/genrb.dsp index 0a87306caf0..9a301021be2 100644 --- a/icu4c/source/tools/genrb/genrb.dsp +++ b/icu4c/source/tools/genrb/genrb.dsp @@ -74,7 +74,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 ..\..\..\lib\debug\icui18n.lib ..\..\..\lib\debug\icuuc.lib toolutil.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\toolutil\Debug" +# ADD LINK32 icui18n.lib icuuc.lib ustdio.lib toolutil.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\toolutil\Debug" /libpath:"..\..\..\lib\debug\\" !ENDIF @@ -95,19 +95,15 @@ SOURCE=.\genrb.c # End Source File # Begin Source File -SOURCE=.\list.c -# End Source File -# Begin Source File - SOURCE=.\parse.c # End Source File # Begin Source File -SOURCE=.\rblist.c +SOURCE=.\read.c # End Source File # Begin Source File -SOURCE=.\read.c +SOURCE=.\reslist.c # End Source File # Begin Source File @@ -117,10 +113,6 @@ SOURCE=.\ustr.c SOURCE=.\util.c # End Source File -# Begin Source File - -SOURCE=.\write.c -# End Source File # End Group # Begin Group "Header Files" @@ -131,19 +123,15 @@ SOURCE=.\error.h # End Source File # Begin Source File -SOURCE=.\list.h -# End Source File -# Begin Source File - SOURCE=.\parse.h # End Source File # Begin Source File -SOURCE=.\rblist.h +SOURCE=.\read.h # End Source File # Begin Source File -SOURCE=.\read.h +SOURCE=.\reslist.h # End Source File # Begin Source File @@ -153,10 +141,6 @@ SOURCE=.\ustr.h SOURCE=.\util.h # End Source File -# Begin Source File - -SOURCE=.\write.h -# End Source File # End Group # Begin Group "Resource Files" diff --git a/icu4c/source/tools/genrb/genrb.dsw b/icu4c/source/tools/genrb/genrb.dsw index 21352a5f828..8658ffd7937 100644 --- a/icu4c/source/tools/genrb/genrb.dsw +++ b/icu4c/source/tools/genrb/genrb.dsw @@ -9,6 +9,33 @@ Package=<5> {{{ }}} +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name testgenrb + End Project Dependency +}}} + +############################################################################### + +Project: "test"=.\test\test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "testgenrb"=.\testgenrb\testgenrb.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + Package=<4> {{{ }}} diff --git a/icu4c/source/tools/genrb/list.c b/icu4c/source/tools/genrb/list.c index dea4c8b423f..797f4e7d112 100644 --- a/icu4c/source/tools/genrb/list.c +++ b/icu4c/source/tools/genrb/list.c @@ -17,6 +17,7 @@ #include "list.h" #include "cmemory.h" +#include "cstring.h" #include "unicode/ustring.h" /* Protos */ @@ -348,11 +349,12 @@ taglist_open(UErrorCode *status) list->fType = eTaggedList; - list->u.fTaggedList.fData = 0; + /*list->u.fTaggedList.fData = 0;*/ + list->u.fTaggedList.fFirst = NULL; list->u.fTaggedList.fCount = 0; - list->u.fTaggedList.fCapacity = 32; + /*list->u.fTaggedList.fCapacity = 32;*/ - taglist_grow(list, status); + /*taglist_grow(list, status);*/ return list; } @@ -361,102 +363,120 @@ void taglist_close(struct SList *list, UErrorCode *status) { - if(U_FAILURE(*status)) return; + struct SStringPair *current; + struct SStringPair *prev; + if(U_FAILURE(*status)) return; if(list->fType != eTaggedList) { *status = U_ILLEGAL_ARGUMENT_ERROR; return; } + + current = list->u.fTaggedList.fFirst; + + while(current != NULL) { + prev = current; + current = current->fNext; + uprv_free(prev); + } + - uprv_free(list->u.fTaggedList.fData); + /*uprv_free(list->u.fTaggedList.fData);*/ list->fType = eEmpty; uprv_free(list); } -static void -taglist_grow(struct SList *list, - UErrorCode *status) -{ - int32_t i; - int32_t newCapacity; - struct SStringPair *newData; - - if(U_FAILURE(*status)) return; - - if(list->fType != eTaggedList) { - *status = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - newCapacity = list->u.fTaggedList.fCapacity << 1; - - /* allocate space for the array of string pairs */ - newData = (struct SStringPair*) - uprv_malloc(sizeof(struct SStringPair) * newCapacity); - if(newData == 0) { - *status = U_MEMORY_ALLOCATION_ERROR; - return; - } - - /* copy each string pair */ - for(i = 0; i < list->u.fTaggedList.fCount; ++i) { - newData[i] = list->u.fTaggedList.fData[i]; - } - - uprv_free(list->u.fTaggedList.fData); - list->u.fTaggedList.fData = newData; - list->u.fTaggedList.fCapacity = newCapacity; -} - void taglist_add(struct SList *list, const UChar *tag, const UChar *data, UErrorCode *status) { - int32_t index; - struct SStringPair pair; + /*int32_t index;*/ + struct SStringPair *pair = NULL; + struct SStringPair *current = NULL; + struct SStringPair *prev = NULL; if(U_FAILURE(*status)) return; - + if(list->fType != eTaggedList) { *status = U_ILLEGAL_ARGUMENT_ERROR; return; } - - pair.fKey = (UChar*) uprv_malloc(sizeof(UChar) * (u_strlen(tag) + 1)); - if(pair.fKey == 0) { + + pair = (struct SStringPair *) uprv_malloc(sizeof(struct SStringPair)); + if(pair->fKey == 0) { *status = U_MEMORY_ALLOCATION_ERROR; return; } - pair.fValue = (UChar*) uprv_malloc(sizeof(UChar) * (u_strlen(data) + 1)); - if(pair.fValue == 0) { + + pair->fKey = (char*) uprv_malloc(sizeof(char) * (u_strlen(tag) + 1)); + if(pair->fKey == 0) { *status = U_MEMORY_ALLOCATION_ERROR; - uprv_free(pair.fKey); + uprv_free(pair); + return; + } + + pair->fValue = (UChar*) uprv_malloc(sizeof(UChar) * (u_strlen(data) + 1)); + if(pair->fValue == 0) { + *status = U_MEMORY_ALLOCATION_ERROR; + uprv_free(pair->fKey); + uprv_free(pair); return; } - u_strcpy(pair.fKey, tag); - u_strcpy(pair.fValue, data); - - index = list->u.fTaggedList.fCount; - - if(list->u.fTaggedList.fCount == list->u.fTaggedList.fCapacity) - taglist_grow(list, status); - - list->u.fTaggedList.fData[index] = pair; ++(list->u.fTaggedList.fCount); + + /*u_strcpy(pair.fKey, tag);*/ + u_UCharsToChars(tag, pair->fKey, u_strlen(tag)+1); + u_strcpy(pair->fValue, data); + + /* is list still empty? */ + if(list->u.fTaggedList.fFirst == NULL) { + list->u.fTaggedList.fFirst = pair; + pair->fNext = NULL; + return; + } else { + current = list->u.fTaggedList.fFirst; + } + + while(current != NULL) { + if(uprv_strcmp(current->fKey, pair->fKey)<0) { + prev = current; + current = current->fNext; + } else { /*we're either in front of list, or in middle*/ + if(prev == NULL) { /*front of the list*/ + list->u.fTaggedList.fFirst = pair; + } else { /*middle of the list*/ + prev->fNext = pair; + } + pair->fNext = current; + return; + } + } + + /* end of list */ + prev->fNext = pair; + pair->fNext = NULL; + + /*index = list->u.fTaggedList.fCount;*/ + + /*if(list->u.fTaggedList.fCount == list->u.fTaggedList.fCapacity)*/ + /*taglist_grow(list, status);*/ + + /*list->u.fTaggedList.fData[index] = pair;*/ } const UChar* taglist_get(const struct SList *list, - const UChar *tag, + const char *tag, UErrorCode *status) { - int32_t i; + /*int32_t i;*/ + struct SStringPair *current; if(U_FAILURE(*status)) return 0; @@ -465,10 +485,20 @@ taglist_get(const struct SList *list, return 0; } - for(i = 0; i < list->u.fTaggedList.fCount; ++i) { - if(u_strcmp(list->u.fTaggedList.fData[i].fKey, tag) == 0) - return list->u.fTaggedList.fData[i].fValue; - } + /* is list still empty? */ + if(list->u.fTaggedList.fFirst == NULL) { + return NULL; + } else { + current = list->u.fTaggedList.fFirst; + } - return 0; + while(current != NULL) { + if(uprv_strcmp(current->fKey, tag)!=0) { + current = current->fNext; + } else { /*we're either in front of list, or in middle*/ + return current->fValue; + } + } + + return NULL; } diff --git a/icu4c/source/tools/genrb/list.h b/icu4c/source/tools/genrb/list.h index aa2758375b8..6e55b7be473 100644 --- a/icu4c/source/tools/genrb/list.h +++ b/icu4c/source/tools/genrb/list.h @@ -49,22 +49,24 @@ void strlist2d_add(struct SList *list, const UChar *s, UErrorCode *status); /* A name/value pair for a tagged list */ struct SStringPair { - UChar *fKey; + char *fKey; UChar *fValue; + struct SStringPair *fNext; }; /* A tagged list */ struct STaggedList { - struct SStringPair *fData; + struct SStringPair *fFirst; + /*struct SStringPair *fData;*/ int32_t fCount; - int32_t fCapacity; + /*int32_t fCapacity;*/ }; struct SList* taglist_open(UErrorCode *status); void taglist_close(struct SList *list, UErrorCode *status); void taglist_add(struct SList *list, const UChar *tag, const UChar *data, UErrorCode *status); -const UChar* taglist_get(const struct SList *list, const UChar *tag, +const UChar* taglist_get(const struct SList *list, const char *tag, UErrorCode *status); /* Types of lists */ diff --git a/icu4c/source/tools/genrb/parse.c b/icu4c/source/tools/genrb/parse.c index 6ed117af1b6..c9f432207d4 100644 --- a/icu4c/source/tools/genrb/parse.c +++ b/icu4c/source/tools/genrb/parse.c @@ -1,7 +1,7 @@ /* ******************************************************************************* * -* Copyright (C) 1998-1999, International Business Machines +* Copyright (C) 1998-2000, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* @@ -12,6 +12,7 @@ * * Date Name Description * 05/26/99 stephen Creation. +* 02/25/00 weiv Overhaul to write udata ******************************************************************************* */ @@ -22,8 +23,7 @@ #include "read.h" #include "unicode/ustdio.h" #include "ustr.h" -#include "list.h" -#include "rblist.h" +#include "reslist.h" #include "unicode/ustring.h" /* Node IDs for the state transition table. */ @@ -95,29 +95,29 @@ struct STransition { comma-delimited list (transition from eList to eIdle on kCloseBrace). */ static struct STransition gTransitionTable [] = { - /* kString kOpenBrace kCloseBrace kComma*/ - {eError,eNOP}, {eError,eNOP}, {eError,eNOP}, {eError,eNOP}, + /* kString kOpenBrace kCloseBrace kComma kColon*/ + /*eError*/ {eError,eNOP}, {eError,eNOP}, {eError,eNOP}, {eError,eNOP}, - {eGotLoc,eOpen}, {eError,eNOP}, {eError,eNOP}, {eError,eNOP}, - {eError,eNOP}, {eIdle,eNOP}, {eError,eNOP}, {eError,eNOP}, + /*eInitial*/ {eGotLoc,eOpen}, {eError,eNOP}, {eError,eNOP}, {eError,eNOP}, + /*eGotLoc*/ {eError,eNOP}, {eIdle,eNOP}, {eError,eNOP}, {eError,eNOP}, + + /*eIdle*/ {eGotTag,eSetTag}, {eError,eNOP}, {eInitial,eClose}, {eError,eNOP}, + /*eGotTag*/ {eError,eNOP}, {eNode5,eNOP}, {eError,eNOP}, {eError,eNOP}, + /*eNode5*/ {eNode6,eNOP}, {e2dArray,eBeg2dList},{eError,eNOP}, {eError,eNOP}, + /*eNode6*/ {eError,eNOP}, {eTagList,eBegTagged},{eIdle,eStr}, {eList,eBegList}, - {eGotTag,eSetTag}, {eError,eNOP}, {eInitial,eClose}, {eError,eNOP}, - {eError,eNOP}, {eNode5,eNOP}, {eError,eNOP}, {eError,eNOP}, - {eNode6,eNOP}, {e2dArray,eBeg2dList},{eError,eNOP}, {eError,eNOP}, - {eError,eNOP}, {eTagList,eBegTagged},{eIdle,eStr}, {eList,eBegList}, - - {eNode8,eListStr}, {eError,eNOP}, {eIdle,eEndList}, {eError,eNOP}, - {eError,eNOP}, {eError,eNOP}, {eIdle,eEndList}, {eList,eNOP}, - - {eNode10,eTaggedStr},{eError,eNOP}, {eError,eNOP}, {eError,eNOP}, - {eError,eNOP}, {eError,eNOP}, {eNode11,eNOP}, {eError,eNOP}, - {eNode12,eNOP}, {eError,eNOP}, {eIdle,eEndTagged},{eError,eNOP}, - {eError,eNOP}, {eTagList,eSubtag}, {eError,eNOP}, {eError,eNOP}, + /*eList*/ {eNode8,eListStr}, {eError,eNOP}, {eIdle,eEndList}, {eError,eNOP}, + /*eNode8*/ {eError,eNOP}, {eError,eNOP}, {eIdle,eEndList}, {eList,eNOP}, + + /*eTagList*/ {eNode10,eTaggedStr},{eError,eNOP}, {eError,eNOP}, {eError,eNOP}, + /*eNode10*/ {eError,eNOP}, {eError,eNOP}, {eNode11,eNOP}, {eError,eNOP}, + /*eNode11*/ {eNode12,eNOP}, {eError,eNOP}, {eIdle,eEndTagged},{eError,eNOP}, + /*eNode12*/ {eError,eNOP}, {eTagList,eSubtag}, {eError,eNOP}, {eError,eNOP}, - {eNode14,e2dStr}, {eError,eNOP}, {eNode15,eNOP}, {eError,eNOP}, - {eError,eNOP}, {eError,eNOP}, {eNode15,eNOP}, {e2dArray,eNOP}, - {eError,eNOP}, {e2dArray,eNewRow}, {eIdle,eEnd2dList},{eNode16,eNOP}, - {eError,eNOP}, {e2dArray,eNewRow}, {eIdle,eEnd2dList},{eError,eNOP} + /*e2dArray*/ {eNode14,e2dStr}, {eError,eNOP}, {eNode15,eNOP}, {eError,eNOP}, + /*eNode14*/ {eError,eNOP}, {eError,eNOP}, {eNode15,eNOP}, {e2dArray,eNOP}, + /*eNode15*/ {eError,eNOP}, {e2dArray,eNewRow}, {eIdle,eEnd2dList},{eNode16,eNOP}, + /*eNode16*/ {eError,eNOP}, {e2dArray,eNewRow}, {eIdle,eEnd2dList},{eError,eNOP} }; /* Row length is 4 */ @@ -157,7 +157,7 @@ static bool_t compareUString(const void* ustr1, const void* ustr2) { * parse ********************************************************************/ -struct SRBItemList* +struct SRBRoot* parse(FileStream *f, const char *cp, UErrorCode *status) { @@ -168,36 +168,47 @@ parse(FileStream *f, const char *cp, struct UString token; struct UString tag; - struct UString subtag; - struct UString localeName; - struct UString keyname; - struct SRBItem *item; - struct SRBItemList *list; - struct SList *current; + char cTag[1024]; + char cSubTag[1024]; + struct SRBRoot *bundle = NULL; + struct SResource *rootTable = NULL; + struct SResource *temp = NULL; + struct SResource *temp1 = NULL; + struct SResource *temp2 = NULL; - /* Hashtable for keeping track of seen tag names */ - struct UHashtable *data; + /* Hashtable for keeping track of seen tag names */ + struct UHashtable *data; - if(U_FAILURE(*status)) return 0; + if(U_FAILURE(*status)) return NULL; - /* setup */ + /* setup */ ustr_init(&token); ustr_init(&tag); - ustr_init(&subtag); - ustr_init(&localeName); - ustr_init(&keyname); +/* + cTag = uprv_malloc(1024); + if(cTag == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } + cSubTag = uprv_malloc(1024); + if(cSubTag == NULL) { + *status = U_MEMORY_ALLOCATION_ERROR; + return NULL; + } +*/ node = eInitial; data = 0; - current = 0; - item = 0; file = u_finit((FILE *)f, 0, cp); /* file = u_finit(f, cp, status); */ - list = rblist_open(status); + + bundle = bundle_open(status); + rootTable = bundle -> fRoot; + if(U_FAILURE(*status) || file == NULL) goto finish; /* iterate through the stream */ @@ -210,7 +221,9 @@ parse(FileStream *f, const char *cp, switch(type) { case tok_EOF: *status = (node == eInitial) ? U_ZERO_ERROR : U_INVALID_FORMAT_ERROR; - setErrorText("Unexpected EOF encountered"); + if(U_FAILURE(*status)) { + setErrorText("Unexpected EOF encountered"); + } goto finish; /*break;*/ @@ -227,153 +240,162 @@ parse(FileStream *f, const char *cp, node = t.fNext; if(node == eError) { - *status = U_INVALID_FORMAT_ERROR; - goto finish; + *status = U_INVALID_FORMAT_ERROR; + goto finish; } switch(t.fAction) { case eNOP: - break; + break; /* Record the last string as the tag name */ case eSetTag: - ustr_cpy(&tag, &token, status); - if(U_FAILURE(*status)) goto finish; - if(get(data, &tag)) { - char *s; - *status = U_INVALID_FORMAT_ERROR; - s = uprv_malloc(1024); - strcpy(s, "Duplicate tag name detected: "); - u_austrcpy(s+strlen(s), tag.fChars); - setErrorText(s); - goto finish; - } - break; + ustr_cpy(&tag, &token, status); + u_UCharsToChars(tag.fChars, cTag, u_strlen(tag.fChars)+1); + if(U_FAILURE(*status)) goto finish; + /*if(uhash_get(data, uhash_hashUString(tag.fChars)) != 0) {*/ + if(get(data, &tag)) { + char *s; + *status = U_INVALID_FORMAT_ERROR; + s = uprv_malloc(1024); + strcpy(s, "Duplicate tag name detected: "); + u_austrcpy(s+strlen(s), tag.fChars); + setErrorText(s); + goto finish; + } + + break; /* Record a singleton string */ case eStr: - if(current != 0) { - *status = U_INTERNAL_PROGRAM_ERROR; - goto finish; - } - current = strlist_open(status); - strlist_add(current, token.fChars, status); - item = make_rbitem(tag.fChars, current, status); - rblist_add(list, item, status); - put(data, &tag, status); - if(U_FAILURE(*status)) goto finish; - current = 0; - item = 0; - break; + if(temp != NULL) { + *status = U_INTERNAL_PROGRAM_ERROR; + goto finish; + } + temp = string_open(bundle, cTag, token.fChars, status); + table_add(rootTable, temp, status); + /*uhash_put(data, tag.fChars, status);*/ + put(data, &tag, status); + if(U_FAILURE(*status)) goto finish; + temp = NULL; + break; /* Begin a string list */ case eBegList: - if(current != 0) { - *status = U_INTERNAL_PROGRAM_ERROR; - goto finish; - } - current = strlist_open(status); - strlist_add(current, token.fChars, status); - if(U_FAILURE(*status)) goto finish; - break; + if(temp != NULL) { + *status = U_INTERNAL_PROGRAM_ERROR; + goto finish; + } + temp = array_open(bundle, cTag, status); + temp1 = string_open(bundle, NULL, token.fChars, status); + array_add(temp, temp1, status); + temp1 = NULL; + if(U_FAILURE(*status)) goto finish; + break; /* Record a comma-delimited list string */ case eListStr: - strlist_add(current, token.fChars, status); - if(U_FAILURE(*status)) goto finish; - break; + temp1 = string_open(bundle, NULL, token.fChars, status); + array_add(temp, temp1, status); + temp1 = NULL; + if(U_FAILURE(*status)) goto finish; + break; /* End a string list */ case eEndList: - put(data, &tag, status); - item = make_rbitem(tag.fChars, current, status); - rblist_add(list, item, status); - if(U_FAILURE(*status)) goto finish; - current = 0; - item = 0; - break; + /*uhash_put(data, tag.fChars, status);*/ + put(data, &tag, status); + table_add(rootTable, temp, status); + temp = NULL; + if(U_FAILURE(*status)) goto finish; + break; case eBeg2dList: - if(current != 0) { - *status = U_INTERNAL_PROGRAM_ERROR; - goto finish; - } - current = strlist2d_open(status); - if(U_FAILURE(*status)) goto finish; - break; + if(temp != NULL) { + *status = U_INTERNAL_PROGRAM_ERROR; + goto finish; + } + temp = array_open(bundle, cTag, status); + temp1 = array_open(bundle, NULL, status); + if(U_FAILURE(*status)) goto finish; + break; case eEnd2dList: - put(data, &tag, status); - item = make_rbitem(tag.fChars, current, status); - rblist_add(list, item, status); - if(U_FAILURE(*status)) goto finish; - current = 0; - item = 0; - break; + /*uhash_put(data, tag.fChars, status);*/ + put(data, &tag, status); + array_add(temp, temp1, status); + table_add(rootTable, temp, status); + temp1 = NULL; + temp = NULL; + if(U_FAILURE(*status)) goto finish; + break; case e2dStr: - strlist2d_add(current, token.fChars, status); - if(U_FAILURE(*status)) goto finish; - break; + temp2 = string_open(bundle, NULL, token.fChars, status); + array_add(temp1, temp2, status); + temp2 = NULL; + if(U_FAILURE(*status)) goto finish; + break; case eNewRow: - strlist2d_newRow(current, status); - if(U_FAILURE(*status)) goto finish; - break; + array_add(temp, temp1, status); + temp1 = array_open(bundle, NULL, status); + if(U_FAILURE(*status)) goto finish; + break; case eBegTagged: - if(current != 0) { - *status = U_INTERNAL_PROGRAM_ERROR; - goto finish; - } - current = taglist_open(status); - ustr_cpy(&subtag, &token, status); - if(U_FAILURE(*status)) goto finish; - break; + if(temp != NULL) { + *status = U_INTERNAL_PROGRAM_ERROR; + goto finish; + } + temp = table_open(bundle, cTag, status); + u_UCharsToChars(token.fChars, cSubTag, u_strlen(token.fChars)+1); + if(U_FAILURE(*status)) goto finish; + break; case eEndTagged: - put(data, &tag, status); - item = make_rbitem(tag.fChars, current, status); - rblist_add(list, item, status); - if(U_FAILURE(*status)) goto finish; - current = 0; - item = 0; - break; + /*uhash_put(data, tag.fChars, status);*/ + put(data, &tag, status); + table_add(rootTable, temp, status); + temp = NULL; + if(U_FAILURE(*status)) goto finish; + break; case eTaggedStr: - taglist_add(current, subtag.fChars, token.fChars, status); - if(U_FAILURE(*status)) goto finish; - break; + temp1 = string_open(bundle, cSubTag, token.fChars, status); + table_add(temp, temp1, status); + temp1 = NULL; + if(U_FAILURE(*status)) goto finish; + break; /* Record the last string as the subtag */ case eSubtag: - ustr_cpy(&subtag, &token, status); - if(U_FAILURE(*status)) goto finish; - if(taglist_get(current, subtag.fChars, status) != 0) { - *status = U_INVALID_FORMAT_ERROR; - setErrorText("Duplicate subtag found in tagged list"); - goto finish; - } - break; + u_UCharsToChars(token.fChars, cSubTag, u_strlen(token.fChars)+1); + if(U_FAILURE(*status)) goto finish; + if(table_get(temp, cSubTag, status) != 0) { + *status = U_INVALID_FORMAT_ERROR; + setErrorText("Duplicate subtag found in tagged list"); + goto finish; + } + break; case eOpen: if(data != 0) { - *status = U_INTERNAL_PROGRAM_ERROR; - goto finish; - } - ustr_cpy(&localeName, &token, status); - rblist_setlocale(list, localeName.fChars, status); - if(U_FAILURE(*status)) goto finish; - data = uhash_open(hashUString, compareUString, status); - uhash_setKeyDeleter(data, freeUString); - break; + *status = U_INTERNAL_PROGRAM_ERROR; + goto finish; + } + bundle_setlocale(bundle, token.fChars, status); + if(U_FAILURE(*status)) goto finish; + data = uhash_open(hashUString, compareUString, status); + uhash_setKeyDeleter(data, freeUString); + break; case eClose: - if(data == 0) { - *status = U_INTERNAL_PROGRAM_ERROR; - goto finish; - } - break; + if(data == 0) { + *status = U_INTERNAL_PROGRAM_ERROR; + goto finish; + } + break; } } @@ -384,17 +406,14 @@ parse(FileStream *f, const char *cp, if(data != 0) uhash_close(data); - if(item != 0) - uprv_free(item); - ustr_deinit(&token); ustr_deinit(&tag); - ustr_deinit(&subtag); - ustr_deinit(&localeName); - ustr_deinit(&keyname); + + /*uprv_free(cTag);*/ + /*uprv_free(cSubTag);*/ if(file != 0) u_fclose(file); - return list; + return bundle; } diff --git a/icu4c/source/tools/genrb/parse.h b/icu4c/source/tools/genrb/parse.h index 1e685df2d25..9c9015938b6 100644 --- a/icu4c/source/tools/genrb/parse.h +++ b/icu4c/source/tools/genrb/parse.h @@ -23,6 +23,6 @@ #include "rblist.h" /* Parse a ResourceBundle text file */ -struct SRBItemList* parse(FileStream *f, const char *cp, UErrorCode *status); +struct SRBRoot* parse(FileStream *f, const char *cp, UErrorCode *status); #endif diff --git a/icu4c/source/tools/genrb/rblist.c b/icu4c/source/tools/genrb/rblist.c index e62f9f0e5b8..33bdd91bef2 100644 --- a/icu4c/source/tools/genrb/rblist.c +++ b/icu4c/source/tools/genrb/rblist.c @@ -19,17 +19,16 @@ #include "ustr.h" #include "unicode/ustring.h" #include "cmemory.h" +#include "cstring.h" -/* Protos */ -static void rblist_grow(struct SRBItemList *list, UErrorCode *status); struct SRBItem* make_rbitem(const UChar *tag, - const struct SList *data, - UErrorCode *status) + const struct SList *data, + UErrorCode *status) { struct SRBItem *item; - UChar *s; + char *s; if(U_FAILURE(*status)) return 0; @@ -39,15 +38,18 @@ make_rbitem(const UChar *tag, return 0; } - s = (UChar*) uprv_malloc(sizeof(UChar) * (u_strlen(tag) + 1)); + //s = (UChar*) uprv_malloc(sizeof(UChar) * (u_strlen(tag) + 1)); + s = (char*) uprv_malloc(sizeof(char) * (u_strlen(tag) + 1)); if(s == 0) { *status = U_MEMORY_ALLOCATION_ERROR; return 0; } - u_strcpy(s, tag); + u_UCharsToChars(tag, s, u_strlen(tag)+1); + //u_strcpy(s, tag); item->fTag = s; item->fData = (struct SList*) data; + item->fNext = NULL; return item; } @@ -66,58 +68,67 @@ rblist_open(UErrorCode *status) } list->fLocale = 0; + list->fFirst = NULL; - list->fData = 0; +// list->fData = 0; list->fCount = 0; list->fCapacity = 32; - - rblist_grow(list, status); + list->fKeys = (char *) uprv_malloc(sizeof(char) * 65532); + list->fKeyPoint = 0; return list; } void rblist_close(struct SRBItemList *list, - UErrorCode *status) + UErrorCode *status) { - int32_t i; +// int32_t i; + struct SRBItem *current; + struct SRBItem *prev = NULL; if(U_FAILURE(*status)) return; - + current = list->fFirst; /* deallocate each list */ - for(i = 0; i < list->fCount; ++i) { +// for(i = 0; i < list->fCount; ++i) { + while(current != NULL) { - switch(list->fData[i]->fData->fType) { - case eStringList: - strlist_close(list->fData[i]->fData, status); - break; +// switch(list->fData[i]->fData->fType) { + switch(current->fData->fType) { + case eStringList: + strlist_close(current->fData, status); + break; - case eStringList2d: - strlist2d_close(list->fData[i]->fData, status); - break; + case eStringList2d: + strlist2d_close(current->fData, status); + break; - case eTaggedList: - taglist_close(list->fData[i]->fData, status); - break; + case eTaggedList: + taglist_close(current->fData, status); + break; - case eEmpty: - break; + case eEmpty: + break; } + prev = current; + current=current->fNext; + uprv_free(prev); } - uprv_free(list->fData); +// uprv_free(list->fData); uprv_free(list->fLocale); + uprv_free(list->fKeys); uprv_free(list); } void rblist_setlocale(struct SRBItemList *list, - const UChar *locale, - UErrorCode *status) + const UChar *locale, + UErrorCode *status) { if(U_FAILURE(*status)) return; /* Allocate enough space */ list->fLocale = (UChar*) uprv_realloc(list->fLocale, - sizeof(UChar) * (u_strlen(locale) + 1)); + sizeof(UChar) * (u_strlen(locale) + 1)); if(list->fLocale == 0) { *status = U_MEMORY_ALLOCATION_ERROR; return; @@ -127,48 +138,53 @@ void rblist_setlocale(struct SRBItemList *list, } void rblist_add(struct SRBItemList *list, - struct SRBItem *s, - UErrorCode *status) + struct SRBItem *s, + UErrorCode *status) { - int32_t index; - - if(U_FAILURE(*status)) return; - - index = list->fCount; - - if(list->fCount == list->fCapacity) - rblist_grow(list, status); - - list->fData[index] = s; - ++(list->fCount); +// int32_t index; + + struct SRBItem *current; + struct SRBItem *prev = NULL; + + if(U_FAILURE(*status)) return; + /* here we need to traverse the list */ + + ++(list->fCount); + + s->fStrKey = list->fKeyPoint; + + uprv_strcpy((list->fKeys)+list->fKeyPoint, s->fTag); + + list->fKeyPoint += uprv_strlen(s->fTag)+1; + + + + /* is list still empty? */ + if(list->fFirst == NULL) { + list->fFirst = s; + s->fNext = NULL; + return; + } else { + current = list->fFirst; + } + + while(current != NULL) { + if(uprv_strcmp(current->fTag, s->fTag)<0) { + prev = current; + current = current->fNext; + } else { /*we're either in front of list, or in middle*/ + if(prev == NULL) { /*front of the list*/ + list->fFirst = s; + } else { /*middle of the list*/ + prev->fNext = s; + } + s->fNext = current; + return; + } + } + + /* end of list */ + prev->fNext = s; + s->fNext = NULL; } -static void -rblist_grow(struct SRBItemList *list, - UErrorCode *status) -{ - int32_t i; - int32_t newCapacity; - struct SRBItem **newData; - - if(U_FAILURE(*status)) return; - - newCapacity = list->fCapacity << 1; - - /* allocate space for the array of SRBItems */ - newData = (struct SRBItem**) - uprv_malloc(sizeof(struct SRBItem*) * newCapacity); - if(newData == 0) { - *status = U_MEMORY_ALLOCATION_ERROR; - return; - } - - /* copy each item */ - for(i = 0; i < list->fCount; ++i) { - newData[i] = list->fData[i]; - } - - uprv_free(list->fData); - list->fData = newData; - list->fCapacity = newCapacity; -} diff --git a/icu4c/source/tools/genrb/rblist.h b/icu4c/source/tools/genrb/rblist.h index 1c72f16e481..6f29f81539d 100644 --- a/icu4c/source/tools/genrb/rblist.h +++ b/icu4c/source/tools/genrb/rblist.h @@ -23,22 +23,27 @@ /* A resource bundle data item */ struct SRBItem { - UChar *fTag; + char *fTag; + int16_t fStrKey; struct SList *fData; + struct SRBItem *fNext; }; -struct SRBItem* make_rbitem(const UChar *tag, const struct SList *data, - UErrorCode *status); - /* A list of RBItems */ struct SRBItemList { UChar *fLocale; - struct SRBItem **fData; + char *fKeys; + int16_t fKeyPoint; int32_t fCount; int32_t fCapacity; + struct SRBItem *fFirst; }; struct SRBItemList* rblist_open(UErrorCode *status); + +struct SRBItem* make_rbitem(const UChar *tag, const struct SList *data, + UErrorCode *status); + void rblist_close(struct SRBItemList *list, UErrorCode *status); void rblist_setlocale(struct SRBItemList *list, const UChar *locale, diff --git a/icu4c/source/tools/genrb/read.c b/icu4c/source/tools/genrb/read.c index 94c33993a5a..8fd802e45e2 100644 --- a/icu4c/source/tools/genrb/read.c +++ b/icu4c/source/tools/genrb/read.c @@ -18,6 +18,7 @@ #include "read.h" #include "error.h" #include "unicode/ustdio.h" +#include "unicode/ustring.h" #define OPENBRACE 0x007B #define CLOSEBRACE 0x007D @@ -27,7 +28,17 @@ #define SLASH 0x002F #define ASTERISK 0x002A #define SPACE 0x0020 +#define COLON 0x003A +U_STRING_DECL(k_start_string, "string", 6); +U_STRING_DECL(k_start_binary, "binary", 6); +U_STRING_DECL(k_start_table, "table", 5); +U_STRING_DECL(k_start_int, "int", 3); +U_STRING_DECL(k_start_array, "array", 5); +U_STRING_DECL(k_start_intvector, "intvector", 9); +U_STRING_DECL(k_start_reserved, "reserved", 8); + +static bool_t didInit=FALSE; /* Protos */ static enum ETokenType getStringToken(UFILE *f, UChar initialChar, @@ -53,21 +64,54 @@ enum ETokenType getNextToken(UFILE *f, struct UString *token, UErrorCode *status) { - UChar c; - - if(U_FAILURE(*status)) return tok_error; + UChar c; - /* Skip whitespace */ - c = getNextChar(f, TRUE, status); - if(U_FAILURE(*status)) return tok_error; - - switch(c) { - case OPENBRACE: return tok_open_brace; - case CLOSEBRACE: return tok_close_brace; - case COMMA: return tok_comma; - case U_EOF: return tok_EOF; - default: return getStringToken(f, c, token, status); - } + enum ETokenType tokenType; + + if(U_FAILURE(*status)) return tok_error; + + /* Skip whitespace */ + c = getNextChar(f, TRUE, status); + if(U_FAILURE(*status)) return tok_error; + + switch(c) { + case OPENBRACE: return tok_open_brace; + case CLOSEBRACE: return tok_close_brace; + case COMMA: return tok_comma; + case U_EOF: return tok_EOF; + case COLON: + c = getNextChar(f, TRUE, status); + tokenType = getStringToken(f, c, token, status); + break; + default: return getStringToken(f, c, token, status); + } + if(!didInit) { + U_STRING_INIT(k_start_string, "string", 6); + U_STRING_INIT(k_start_binary, "binary", 6); + U_STRING_INIT(k_start_table, "table", 5); + U_STRING_INIT(k_start_int, "int", 3); + U_STRING_INIT(k_start_array, "array", 5); + U_STRING_INIT(k_start_intvector, "intvector", 9); + U_STRING_INIT(k_start_reserved, "reserved", 8); + didInit=TRUE; + } + if(u_strcmp(token->fChars, k_start_string) == 0) { + return(tok_start_string); + } else if(u_strcmp(token->fChars, k_start_binary) == 0) { + return(tok_start_binary); + } else if(u_strcmp(token->fChars, k_start_table) == 0) { + return(tok_start_table); + } else if(u_strcmp(token->fChars, k_start_int) == 0) { + return(tok_start_int); + } else if(u_strcmp(token->fChars, k_start_array) == 0) { + return(tok_start_array); + } else if(u_strcmp(token->fChars, k_start_intvector) == 0) { + return(tok_start_intvector); + } else if(u_strcmp(token->fChars, k_start_reserved) == 0) { + return(tok_start_reserved); + } else { + return tok_error; + } } /* Copy a string token into the given UnicodeString. Upon entry, we @@ -148,7 +192,8 @@ static enum ETokenType getStringToken(UFILE *f, if(c == QUOTE || c == OPENBRACE || c == CLOSEBRACE - || c == COMMA) + || c == COMMA + || c == COLON) { u_fungetc(c, f); /*u_fungetc(c, f, status);*/ @@ -170,7 +215,7 @@ static enum ETokenType getStringToken(UFILE *f, if(U_FAILURE(*status)) return tok_string; - if(c == OPENBRACE || c == CLOSEBRACE || c == COMMA) { + if(c == OPENBRACE || c == CLOSEBRACE || c == COMMA || c == COLON) { u_fungetc(c, f); /*u_fungetc(c, f, status);*/ return tok_string; diff --git a/icu4c/source/tools/genrb/read.h b/icu4c/source/tools/genrb/read.h index dd99947bd19..5abbdc77e3b 100644 --- a/icu4c/source/tools/genrb/read.h +++ b/icu4c/source/tools/genrb/read.h @@ -29,10 +29,17 @@ enum ETokenType tok_open_brace, /* An opening brace character */ tok_close_brace, /* A closing brace character */ tok_comma, /* A comma */ + tok_start_string, /* :String */ + tok_start_binary, /* :Binary */ + tok_start_table, /* :Table */ + tok_start_int, /* :Integer */ + tok_start_array, /* :Array */ + tok_start_intvector, /* :IntVector */ + tok_start_reserved, /* :Reserved - treat like a string */ tok_EOF, /* End of the file has been reached successfully */ tok_error, /* An error, such an unterminated quoted string */ - tok_token_type_count = 4 /* Number of "real" token types */ + tok_token_type_count = 11 /* Number of "real" token types */ }; enum ETokenType getNextToken(UFILE *f, diff --git a/icu4c/source/tools/genrb/write.c b/icu4c/source/tools/genrb/write.c index 7dc3c22e455..b3662c02f73 100644 --- a/icu4c/source/tools/genrb/write.c +++ b/icu4c/source/tools/genrb/write.c @@ -27,11 +27,12 @@ /* Protos */ static void write_ustring(FileStream *rb, const UChar *data); -static void write_strlist(FileStream *rb, const UChar *name, +static void write_string(FileStream *rb, const char *data); +static void write_strlist(FileStream *rb, const char *name, const struct SStringList *list); -static void write_strlist2d(FileStream *rb, const UChar *name, +static void write_strlist2d(FileStream *rb, const char *name, const struct SStringList2d *list); -static void write_taglist(FileStream *rb, const UChar *name, +static void write_taglist(FileStream *rb, const char *name, const struct STaggedList *list); /* Special values */ @@ -65,10 +66,21 @@ write_ustring(FileStream *rb, T_FileStream_write(rb, data, sizeof(UChar) * len); } +static void +write_string(FileStream *rb, + const char *data) { + int32_t len; + + len = uprv_strlen(data); + T_FileStream_write(rb, &len, sizeof(len)); + + T_FileStream_write(rb, data, sizeof(char) * len); +} + /* Write a string list */ static void write_strlist(FileStream *rb, - const UChar *name, + const char *name, const struct SStringList *list) { int32_t i; @@ -77,7 +89,7 @@ write_strlist(FileStream *rb, T_FileStream_write(rb, &sSTRINGLIST, sizeof(sSTRINGLIST)); /* Write the name of this string list */ - write_ustring(rb, name); + write_string(rb, name); /* Write the item count */ T_FileStream_write(rb, &list->fCount, sizeof(list->fCount)); @@ -91,7 +103,7 @@ write_strlist(FileStream *rb, /* Write a 2-d string list */ static void write_strlist2d(FileStream *rb, - const UChar *name, + const char *name, const struct SStringList2d *list) { int32_t i, j; @@ -101,7 +113,7 @@ write_strlist2d(FileStream *rb, T_FileStream_write(rb, &sSTRINGLIST2D, sizeof(sSTRINGLIST2D)); /* Write the name of this 2-d string list */ - write_ustring(rb, name); + write_string(rb, name); /* Write the row count */ T_FileStream_write(rb, &list->fRowCount, sizeof(list->fRowCount)); @@ -124,25 +136,34 @@ write_strlist2d(FileStream *rb, /* Write a tagged list */ static void write_taglist(FileStream *rb, - const UChar *name, + const char *name, const struct STaggedList *list) { - int32_t i; +// int32_t i; + struct SStringPair *current; /* Write out the value indicating this is a tagged list */ T_FileStream_write(rb, &sTAGGEDLIST, sizeof(sTAGGEDLIST)); /* Write the name of this tagged list */ - write_ustring(rb, name); + write_string(rb, name); /* Write the item count */ T_FileStream_write(rb, &list->fCount, sizeof(list->fCount)); /* Write out each key/value pair */ - for(i = 0; i < list->fCount; ++i) { - write_ustring(rb, list->fData[i].fKey); - write_ustring(rb, list->fData[i].fValue); + current = list->fFirst; + while(current != NULL) { + write_string(rb, current->fKey); + write_ustring(rb, current->fValue); + current = current->fNext; } + + +// for(i = 0; i < list->fCount; ++i) { +// write_ustring(rb, list->fData[i].fKey); +// write_ustring(rb, list->fData[i].fValue); +// } } /* Write a parsed SRBItemList to a file */ @@ -151,7 +172,7 @@ rb_write(FileStream *f, struct SRBItemList *data, UErrorCode *status) { - int32_t i; +// int32_t i; struct SRBItem *item; if(U_FAILURE(*status)) return; @@ -162,10 +183,13 @@ rb_write(FileStream *f, /* Write the locale name to the file */ write_ustring(f, data->fLocale); - /* Successively write each list item */ - for(i = 0; i < data->fCount; ++i) { + item = data->fFirst; - item = data->fData[i]; + /* Successively write each list item */ +// for(i = 0; i < data->fCount; ++i) { + while(item != NULL) { + +// item = data->fData[i]; switch(item->fData->fType) { case eStringList: @@ -188,6 +212,7 @@ rb_write(FileStream *f, goto finish; /*break;*/ } + item = item->fNext; } /* Indicate the end of the data */ diff --git a/icu4c/source/tools/makedata.mak b/icu4c/source/tools/makedata.mak index c99f6c677ac..95613cceb0f 100644 --- a/icu4c/source/tools/makedata.mak +++ b/icu4c/source/tools/makedata.mak @@ -24,14 +24,16 @@ CFG=Debug ICUDATA=$(ICUP)\icu\data ICU_DATA=$(ICUDATA)\ DATA_PATH=$(ICUP)\icu\data^\ -TRANS=translit^\ +#TRANS=translit^\ TEST=..\source\test\testdata^\ +TESTDATA=$(ICUP)\icu\source\test\testdata^\ ICUTOOLS=$(ICUP)\icu\source\tools !ENDIF LINK32 = link.exe LINK32_FLAGS = /out:"$(ICUDATA)/icudata.dll" /DLL /NOENTRY /base:"0x4ad00000" /comment:" Copyright (C) 1999-2000 International Business Machines Corporation and others. All Rights Reserved. " -CPP_FLAGS = /I$(ICUP)\icu\include /GD /c +#CPP_FLAGS = /I$(ICUP)\icu\include /GD /c +CPP_FLAGS = /I$(ICUP)\icu\include /GD /c /Fo$@ #Here we test if configuration is given !IF "$(CFG)" != "Release" && "$(CFG)" != "release" && "$(CFG)" != "Debug" && "$(CFG)" != "debug" @@ -92,7 +94,13 @@ GENRB_SOURCE=$(GENRB_SOURCE) $(GENRB_SOURCE_LOCAL) !ELSE !ERROR ERROR: cannot find "genrbfiles.mk" !ENDIF -RB_FILES = $(GENRB_SOURCE:.txt=.res) +RB_FILES = $(GENRB_SOURCE:.txt=.res) +TRANSLIT_FILES = $(TRANSLIT_SOURCE:.txt=.res) +#TRANSLIT_SOURCE = $(TRANSLIT_SOURCE: = translit\) +!MESSAGE $(TRANSLIT_SOURCE) $(RB_FILES) +C_RB_FILES = $(RB_FILES:.res=_res.c) $(TRANSLIT_FILES:.res=_res.c) +OBJ_RB_FILES = $(C_RB_FILES:.c=.obj) + # Read list of resource bundle files for colation !IF EXISTS("$(ICUTOOLS)\gencol\gencolfiles.mk") @@ -110,13 +118,13 @@ COL_FILES = $(GENCOL_SOURCE:.txt=.col) # This target should build all the data files -ALL : GODATA $(RB_FILES) $(CNV_FILES) $(COL_FILES) test.dat base_test.dat test_dat.dll base_test_dat.dll base_dat.dll icudata.dat icudata.dll GOBACK +ALL : GODATA test.dat base_test.dat test_dat.dll base_test_dat.dll base_dat.dll icudata.dat $(TESTDATA)testdata.dll icudata.dll $(COL_FILES) GOBACK @echo All targets are up to date BRK_FILES = $(ICUDATA)\sent.brk $(ICUDATA)\char.brk $(ICUDATA)\line.brk $(ICUDATA)\word.brk $(ICUDATA)\line_th.brk $(ICUDATA)\word_th.brk BRK_CSOURCES = $(BRK_FILES:.brk=_brk.c) -CPP_SOURCES = $(C_CNV_FILES) uprops_dat.c unames_dat.c cnvalias_dat.c tz_dat.c $(BRK_CSOURCES) +CPP_SOURCES = $(C_CNV_FILES) uprops_dat.c unames_dat.c cnvalias_dat.c tz_dat.c $(BRK_CSOURCES) $(C_RB_FILES) LINK32_OBJS = $(CPP_SOURCES:.c=.obj) # target for DLL @@ -158,7 +166,35 @@ icudata.dll: icudata.dat LINK32_TEST_FLAGS = /out:"$(ICUDATA)/test_dat.dll" /DLL /NOENTRY LINK32_BASE_TEST_FLAGS = /out:"$(ICUDATA)/base_test_dat.dll" /DLL /NOENTRY LINK32_BASE_FLAGS = /out:"$(ICUDATA)/base_dat.dll" /DLL /NOENTRY +LINK32_TESTDATA_FLAGS = /out:"$(TESTDATA)/testdata.dll" /DLL /NOENTRY +#Targets for testdata.dll +testdata.dll : $(TESTDATA)testdata.dll + @cd $(TESTDATA) + +$(TESTDATA)testdata.dll : $(TESTDATA)root_res.obj $(TESTDATA)te_res.obj $(TESTDATA)te_IN_res.obj + @echo Creating DLL file + @cd $(TESTDATA) + @$(LINK32) @<< +$(LINK32_TESTDATA_FLAGS) root_res.obj te_res.obj te_IN_res.obj +<< + +$(TESTDATA)root_res.c $(TESTDATA)te_res.c $(TESTDATA)te_IN_res.c : $(TESTDATA)root.res $(TESTDATA)te.res $(TESTDATA)te_IN.res + @echo generating .c file for testdata + @cd $(TESTDATA) + @$(ICUTOOLS)\genccode\$(CFG)\genccode $? + +#Targets for testdata.dat +#testdata.dat : $(TESTDATA)root.res $(TESTDATA)te.res $(TESTDATA)te_IN.res +# @echo Creating testdata.dat +# @set ICU_DATA=$(ICUDATA) +# @cd $(TESTDATA) +# @$(ICUTOOLS)\gencmn\$(CFG)\gencmn 1000000 << +#root.res +#te.res +#te_IN.res +#<< + # Targets for test.dat test.dat : @echo Creating data file for test @@ -175,6 +211,7 @@ test_dat.obj : test_dat.c $(CPP_FLAGS) $(ICUDATA)\$? << + #Targets for base_test.dat base_test.dat : @echo Creating base data file test @@ -227,7 +264,8 @@ $(ICUDATA)\word_th.brk : $(ICUDATA)\word_thLE.brk copy $(ICUDATA)\word_thLE.brk $(ICUDATA)\word_th.brk # target for memory mapped file -icudata.dat : $(CNV_FILES) $(BRK_FILES) uprops.dat unames.dat cnvalias.dat tz.dat + +icudata.dat : $(CNV_FILES) $(BRK_FILES) uprops.dat unames.dat cnvalias.dat tz.dat $(RB_FILES) $(TRANSLIT_FILES) @echo Creating memory-mapped file @cd $(ICUDATA) @$(ICUTOOLS)\gencmn\$(CFG)\gencmn -c -d $(ICUDATA) 1000000 << @@ -235,12 +273,22 @@ $(ICUDATA)\uprops.dat $(ICUDATA)\unames.dat $(ICUDATA)\cnvalias.dat $(ICUDATA)\tz.dat -$(BRK_FILES:.brk =.brk -) $(CNV_FILES:.cnv =.cnv ) +$(RB_FILES:.res =.res +) +$(TRANSLIT_FILES:.res =.res +) +$(BRK_FILES:.brk =.brk +) << +# nothing works without this target, but we're making +# these files while creating converters +$(C_RB_FILES) : $(RB_FILES) + @$(ICUTOOLS)\genccode\$(CFG)\genccode $(RB_FILES) + + # nothing works without this target, but we're making # these files while creating converters $(C_CNV_FILES) : $(CNV_FILES) @@ -286,11 +334,18 @@ CLEAN : -@erase "*.res" @cd $(ICUTOOLS) +{$(ICUDATA)$(TRANS)}$(TRANSLIT_FILES) : $(TRANSLIT_SOURCE) + @echo Making transliteration bundles + cd $(ICUDATA)$(TRANS) + set ICU_DATA=$(ICUDATA) + $(ICUTOOLS)\genrb\$(CFG)\genrb -s$(ICUDATA)$(TRANS) -d$(ICUDATA) $(TRANSLIT_SOURCE) + # Inference rule for creating resource bundles -.txt.res:: +.txt.res: @echo Making Resource Bundle files - @cd $(ICUDATA) - @$(ICUTOOLS)\genrb\$(CFG)\genrb $< + @echo cd $(ICUDATA) + @echo set ICU_DATA=$(ICUDATA) + $(ICUTOOLS)\genrb\$(CFG)\genrb -s$(@D) -d$(@D) $(?F) # Inference rule for creating converters, with a kludge to create # c versions of converters at the same time @@ -306,13 +361,14 @@ CLEAN : .txt.col:: @echo Making Collation files @cd $(ICUDATA) - @$(ICUTOOLS)\genrb\$(CFG)\genrb $< + @set ICU_DATA=$(ICUDATA) + $(ICUTOOLS)\gencol\$(CFG)\gencol $< # Inference rule for compiling :) -.c.obj:: +.c.obj: @cd $(ICUDATA) @$(CPP) @<< -$(CPP_FLAGS) $< +$(CPP_FLAGS) $? << # Targets for uprops.dat