LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - dtitvinf.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 337 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 35 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*******************************************************************************
       4             : * Copyright (C) 2008-2016, International Business Machines Corporation and
       5             : * others. All Rights Reserved.
       6             : *******************************************************************************
       7             : *
       8             : * File DTITVINF.CPP
       9             : *
      10             : *******************************************************************************
      11             : */
      12             : 
      13             : #include "unicode/dtitvinf.h"
      14             : 
      15             : 
      16             : #if !UCONFIG_NO_FORMATTING
      17             : 
      18             : //TODO: define it in compiler time
      19             : //#define DTITVINF_DEBUG 1
      20             : 
      21             : 
      22             : #ifdef DTITVINF_DEBUG
      23             : #include <iostream>
      24             : #endif
      25             : 
      26             : #include "cmemory.h"
      27             : #include "cstring.h"
      28             : #include "unicode/msgfmt.h"
      29             : #include "unicode/uloc.h"
      30             : #include "unicode/ures.h"
      31             : #include "dtitv_impl.h"
      32             : #include "charstr.h"
      33             : #include "hash.h"
      34             : #include "gregoimp.h"
      35             : #include "uresimp.h"
      36             : #include "hash.h"
      37             : #include "gregoimp.h"
      38             : #include "uresimp.h"
      39             : 
      40             : 
      41             : U_NAMESPACE_BEGIN
      42             : 
      43             : 
      44             : #ifdef DTITVINF_DEBUG
      45             : #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
      46             : #endif
      47             : 
      48           0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalInfo)
      49             : 
      50             : static const char gCalendarTag[]="calendar";
      51             : static const char gGregorianTag[]="gregorian";
      52             : static const char gIntervalDateTimePatternTag[]="intervalFormats";
      53             : static const char gFallbackPatternTag[]="fallback";
      54             : 
      55             : // {0}
      56             : static const UChar gFirstPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET};
      57             : // {1}
      58             : static const UChar gSecondPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET};
      59             : 
      60             : // default fall-back
      61             : static const UChar gDefaultFallbackPattern[] = {LEFT_CURLY_BRACKET, DIGIT_ZERO, RIGHT_CURLY_BRACKET, SPACE, EN_DASH, SPACE, LEFT_CURLY_BRACKET, DIGIT_ONE, RIGHT_CURLY_BRACKET, 0};
      62             : 
      63           0 : DateIntervalInfo::DateIntervalInfo(UErrorCode& status)
      64             : :   fFallbackIntervalPattern(gDefaultFallbackPattern),
      65             :     fFirstDateInPtnIsLaterDate(false),
      66           0 :     fIntervalPatterns(NULL)
      67             : {
      68           0 :     fIntervalPatterns = initHash(status);
      69           0 : }
      70             : 
      71             : 
      72             : 
      73           0 : DateIntervalInfo::DateIntervalInfo(const Locale& locale, UErrorCode& status)
      74             : :   fFallbackIntervalPattern(gDefaultFallbackPattern),
      75             :     fFirstDateInPtnIsLaterDate(false),
      76           0 :     fIntervalPatterns(NULL)
      77             : {
      78           0 :     initializeData(locale, status);
      79           0 : }
      80             : 
      81             : 
      82             : 
      83             : void
      84           0 : DateIntervalInfo::setIntervalPattern(const UnicodeString& skeleton,
      85             :                                      UCalendarDateFields lrgDiffCalUnit,
      86             :                                      const UnicodeString& intervalPattern,
      87             :                                      UErrorCode& status) {
      88             : 
      89           0 :     if ( lrgDiffCalUnit == UCAL_HOUR_OF_DAY ) {
      90           0 :         setIntervalPatternInternally(skeleton, UCAL_AM_PM, intervalPattern, status);
      91           0 :         setIntervalPatternInternally(skeleton, UCAL_HOUR, intervalPattern, status);
      92           0 :     } else if ( lrgDiffCalUnit == UCAL_DAY_OF_MONTH ||
      93             :                 lrgDiffCalUnit == UCAL_DAY_OF_WEEK ) {
      94           0 :         setIntervalPatternInternally(skeleton, UCAL_DATE, intervalPattern, status);
      95             :     } else {
      96           0 :         setIntervalPatternInternally(skeleton, lrgDiffCalUnit, intervalPattern, status);
      97             :     }
      98           0 : }
      99             : 
     100             : 
     101             : void
     102           0 : DateIntervalInfo::setFallbackIntervalPattern(
     103             :                                     const UnicodeString& fallbackPattern,
     104             :                                     UErrorCode& status) {
     105           0 :     if ( U_FAILURE(status) ) {
     106           0 :         return;
     107             :     }
     108             :     int32_t firstPatternIndex = fallbackPattern.indexOf(gFirstPattern,
     109           0 :                         UPRV_LENGTHOF(gFirstPattern), 0);
     110             :     int32_t secondPatternIndex = fallbackPattern.indexOf(gSecondPattern,
     111           0 :                         UPRV_LENGTHOF(gSecondPattern), 0);
     112           0 :     if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) {
     113           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
     114           0 :         return;
     115             :     }
     116           0 :     if ( firstPatternIndex > secondPatternIndex ) {
     117           0 :         fFirstDateInPtnIsLaterDate = true;
     118             :     }
     119           0 :     fFallbackIntervalPattern = fallbackPattern;
     120             : }
     121             : 
     122             : 
     123             : 
     124           0 : DateIntervalInfo::DateIntervalInfo(const DateIntervalInfo& dtitvinf)
     125             : :   UObject(dtitvinf),
     126           0 :     fIntervalPatterns(NULL)
     127             : {
     128           0 :     *this = dtitvinf;
     129           0 : }
     130             : 
     131             : 
     132             : 
     133             : DateIntervalInfo&
     134           0 : DateIntervalInfo::operator=(const DateIntervalInfo& dtitvinf) {
     135           0 :     if ( this == &dtitvinf ) {
     136           0 :         return *this;
     137             :     }
     138             : 
     139           0 :     UErrorCode status = U_ZERO_ERROR;
     140           0 :     deleteHash(fIntervalPatterns);
     141           0 :     fIntervalPatterns = initHash(status);
     142           0 :     copyHash(dtitvinf.fIntervalPatterns, fIntervalPatterns, status);
     143           0 :     if ( U_FAILURE(status) ) {
     144           0 :         return *this;
     145             :     }
     146             : 
     147           0 :     fFallbackIntervalPattern = dtitvinf.fFallbackIntervalPattern;
     148           0 :     fFirstDateInPtnIsLaterDate = dtitvinf.fFirstDateInPtnIsLaterDate;
     149           0 :     return *this;
     150             : }
     151             : 
     152             : 
     153             : DateIntervalInfo*
     154           0 : DateIntervalInfo::clone() const {
     155           0 :     return new DateIntervalInfo(*this);
     156             : }
     157             : 
     158             : 
     159           0 : DateIntervalInfo::~DateIntervalInfo() {
     160           0 :     deleteHash(fIntervalPatterns);
     161           0 :     fIntervalPatterns = NULL;
     162           0 : }
     163             : 
     164             : 
     165             : UBool
     166           0 : DateIntervalInfo::operator==(const DateIntervalInfo& other) const {
     167             :     UBool equal = (
     168           0 :       fFallbackIntervalPattern == other.fFallbackIntervalPattern &&
     169           0 :       fFirstDateInPtnIsLaterDate == other.fFirstDateInPtnIsLaterDate );
     170             : 
     171           0 :     if ( equal == TRUE ) {
     172           0 :         equal = fIntervalPatterns->equals(*(other.fIntervalPatterns));
     173             :     }
     174             : 
     175           0 :     return equal;
     176             : }
     177             : 
     178             : 
     179             : UnicodeString&
     180           0 : DateIntervalInfo::getIntervalPattern(const UnicodeString& skeleton,
     181             :                                      UCalendarDateFields field,
     182             :                                      UnicodeString& result,
     183             :                                      UErrorCode& status) const {
     184           0 :     if ( U_FAILURE(status) ) {
     185           0 :         return result;
     186             :     }
     187             : 
     188           0 :     const UnicodeString* patternsOfOneSkeleton = (UnicodeString*) fIntervalPatterns->get(skeleton);
     189           0 :     if ( patternsOfOneSkeleton != NULL ) {
     190           0 :         IntervalPatternIndex index = calendarFieldToIntervalIndex(field, status);
     191           0 :         if ( U_FAILURE(status) ) {
     192           0 :             return result;
     193             :         }
     194           0 :         const UnicodeString& intervalPattern =  patternsOfOneSkeleton[index];
     195           0 :         if ( !intervalPattern.isEmpty() ) {
     196           0 :             result = intervalPattern;
     197             :         }
     198             :     }
     199           0 :     return result;
     200             : }
     201             : 
     202             : 
     203             : UBool
     204           0 : DateIntervalInfo::getDefaultOrder() const {
     205           0 :     return fFirstDateInPtnIsLaterDate;
     206             : }
     207             : 
     208             : 
     209             : UnicodeString&
     210           0 : DateIntervalInfo::getFallbackIntervalPattern(UnicodeString& result) const {
     211           0 :     result = fFallbackIntervalPattern;
     212           0 :     return result;
     213             : }
     214             : 
     215             : #define ULOC_LOCALE_IDENTIFIER_CAPACITY (ULOC_FULLNAME_CAPACITY + 1 + ULOC_KEYWORD_AND_VALUES_CAPACITY)
     216             : 
     217             : 
     218             : static const int32_t PATH_PREFIX_LENGTH = 17;
     219             : static const UChar PATH_PREFIX[] = {SOLIDUS, CAP_L, CAP_O, CAP_C, CAP_A, CAP_L, CAP_E, SOLIDUS,
     220             :                                     LOW_C, LOW_A, LOW_L, LOW_E, LOW_N, LOW_D, LOW_A, LOW_R, SOLIDUS};
     221             : static const int32_t PATH_SUFFIX_LENGTH = 16;
     222             : static const UChar PATH_SUFFIX[] = {SOLIDUS, LOW_I, LOW_N, LOW_T, LOW_E, LOW_R, LOW_V, LOW_A,
     223             :                                     LOW_L, CAP_F, LOW_O, LOW_R, LOW_M, LOW_A, LOW_T, LOW_S};
     224             : 
     225             : /**
     226             :  * Sink for enumerating all of the date interval skeletons.
     227             :  */
     228             : struct DateIntervalInfo::DateIntervalSink : public ResourceSink {
     229             : 
     230             :     // Output data
     231             :     DateIntervalInfo &dateIntervalInfo;
     232             : 
     233             :     // Next calendar type
     234             :     UnicodeString nextCalendarType;
     235             : 
     236           0 :     DateIntervalSink(DateIntervalInfo &diInfo, const char *currentCalendarType)
     237           0 :             : dateIntervalInfo(diInfo), nextCalendarType(currentCalendarType, -1, US_INV) { }
     238             :     virtual ~DateIntervalSink();
     239             : 
     240           0 :     virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &errorCode) {
     241           0 :         if (U_FAILURE(errorCode)) { return; }
     242             : 
     243             :         // Iterate over all the calendar entries and only pick the 'intervalFormats' table.
     244           0 :         ResourceTable dateIntervalData = value.getTable(errorCode);
     245           0 :         if (U_FAILURE(errorCode)) { return; }
     246           0 :         for (int32_t i = 0; dateIntervalData.getKeyAndValue(i, key, value); i++) {
     247           0 :             if (uprv_strcmp(key, gIntervalDateTimePatternTag) != 0) {
     248           0 :                 continue;
     249             :             }
     250             : 
     251             :             // Handle aliases and tables. Ignore the rest.
     252           0 :             if (value.getType() == URES_ALIAS) {
     253             :                 // Get the calendar type for the alias path.
     254           0 :                 const UnicodeString &aliasPath = value.getAliasUnicodeString(errorCode);
     255           0 :                 if (U_FAILURE(errorCode)) { return; }
     256             : 
     257           0 :                 nextCalendarType.remove();
     258           0 :                 getCalendarTypeFromPath(aliasPath, nextCalendarType, errorCode);
     259             : 
     260           0 :                 if (U_FAILURE(errorCode)) {
     261           0 :                     resetNextCalendarType();
     262             :                 }
     263           0 :                 break;
     264             : 
     265           0 :             } else if (value.getType() == URES_TABLE) {
     266             :                 // Iterate over all the skeletons in the 'intervalFormat' table.
     267           0 :                 ResourceTable skeletonData = value.getTable(errorCode);
     268           0 :                 if (U_FAILURE(errorCode)) { return; }
     269           0 :                 for (int32_t j = 0; skeletonData.getKeyAndValue(j, key, value); j++) {
     270           0 :                     if (value.getType() == URES_TABLE) {
     271             :                         // Process the skeleton
     272           0 :                         processSkeletonTable(key, value, errorCode);
     273           0 :                         if (U_FAILURE(errorCode)) { return; }
     274             :                     }
     275             :                 }
     276           0 :                 break;
     277             :             }
     278             :         }
     279             :     }
     280             : 
     281             :     /**
     282             :      * Processes the patterns for a skeleton table
     283             :      */
     284           0 :     void processSkeletonTable(const char *key, ResourceValue &value, UErrorCode &errorCode) {
     285           0 :         if (U_FAILURE(errorCode)) { return; }
     286             : 
     287             :         // Iterate over all the patterns in the current skeleton table
     288           0 :         const char *currentSkeleton = key;
     289           0 :         ResourceTable patternData = value.getTable(errorCode);
     290           0 :         if (U_FAILURE(errorCode)) { return; }
     291           0 :         for (int32_t k = 0; patternData.getKeyAndValue(k, key, value); k++) {
     292           0 :             if (value.getType() == URES_STRING) {
     293             :                 // Process the key
     294           0 :                 UCalendarDateFields calendarField = validateAndProcessPatternLetter(key);
     295             : 
     296             :                 // If the calendar field has a valid value
     297           0 :                 if (calendarField < UCAL_FIELD_COUNT) {
     298             :                     // Set the interval pattern
     299           0 :                     setIntervalPatternIfAbsent(currentSkeleton, calendarField, value, errorCode);
     300           0 :                     if (U_FAILURE(errorCode)) { return; }
     301             :                 }
     302             :             }
     303             :         }
     304             :     }
     305             : 
     306             :     /**
     307             :      * Extracts the calendar type from the path.
     308             :      */
     309           0 :     static void getCalendarTypeFromPath(const UnicodeString &path, UnicodeString &calendarType,
     310             :                                         UErrorCode &errorCode) {
     311           0 :         if (U_FAILURE(errorCode)) { return; }
     312             : 
     313           0 :         if (!path.startsWith(PATH_PREFIX, PATH_PREFIX_LENGTH) || !path.endsWith(PATH_SUFFIX, PATH_SUFFIX_LENGTH)) {
     314           0 :             errorCode = U_INVALID_FORMAT_ERROR;
     315           0 :             return;
     316             :         }
     317             : 
     318           0 :         path.extractBetween(PATH_PREFIX_LENGTH, path.length() - PATH_SUFFIX_LENGTH, calendarType);
     319             :     }
     320             : 
     321             :     /**
     322             :      * Validates and processes the pattern letter
     323             :      */
     324           0 :     UCalendarDateFields validateAndProcessPatternLetter(const char *patternLetter) {
     325             :         // Check that patternLetter is just one letter
     326             :         char c0;
     327           0 :         if ((c0 = patternLetter[0]) != 0 && patternLetter[1] == 0) {
     328             :             // Check that the pattern letter is accepted
     329           0 :             if (c0 == 'y') {
     330           0 :                 return UCAL_YEAR;
     331           0 :             } else if (c0 == 'M') {
     332           0 :                 return UCAL_MONTH;
     333           0 :             } else if (c0 == 'd') {
     334           0 :                 return UCAL_DATE;
     335           0 :             } else if (c0 == 'a') {
     336           0 :                 return UCAL_AM_PM;
     337           0 :             } else if (c0 == 'h' || c0 == 'H') {
     338           0 :                 return UCAL_HOUR;
     339           0 :             } else if (c0 == 'm') {
     340           0 :                 return UCAL_MINUTE;
     341             :             }// TODO(ticket:12190): Why icu4c doesn't accept the calendar field "s" but icu4j does?
     342             :         }
     343           0 :         return UCAL_FIELD_COUNT;
     344             :     }
     345             : 
     346             :     /**
     347             :      * Stores the interval pattern for the current skeleton in the internal data structure
     348             :      * if it's not present.
     349             :      */
     350           0 :     void setIntervalPatternIfAbsent(const char *currentSkeleton, UCalendarDateFields lrgDiffCalUnit,
     351             :                                     const ResourceValue &value, UErrorCode &errorCode) {
     352             :         // Check if the pattern has already been stored on the data structure
     353             :         IntervalPatternIndex index =
     354           0 :             dateIntervalInfo.calendarFieldToIntervalIndex(lrgDiffCalUnit, errorCode);
     355           0 :         if (U_FAILURE(errorCode)) { return; }
     356             : 
     357           0 :         UnicodeString skeleton(currentSkeleton, -1, US_INV);
     358             :         UnicodeString* patternsOfOneSkeleton =
     359           0 :             (UnicodeString*)(dateIntervalInfo.fIntervalPatterns->get(skeleton));
     360             : 
     361           0 :         if (patternsOfOneSkeleton == NULL || patternsOfOneSkeleton[index].isEmpty()) {
     362           0 :             UnicodeString pattern = value.getUnicodeString(errorCode);
     363           0 :             dateIntervalInfo.setIntervalPatternInternally(skeleton, lrgDiffCalUnit,
     364           0 :                                                           pattern, errorCode);
     365             :         }
     366             :     }
     367             : 
     368           0 :     const UnicodeString &getNextCalendarType() {
     369           0 :         return nextCalendarType;
     370             :     }
     371             : 
     372           0 :     void resetNextCalendarType() {
     373           0 :         nextCalendarType.setToBogus();
     374           0 :     }
     375             : };
     376             : 
     377             : // Virtual destructors must be defined out of line.
     378           0 : DateIntervalInfo::DateIntervalSink::~DateIntervalSink() {}
     379             : 
     380             : 
     381             : 
     382             : void
     383           0 : DateIntervalInfo::initializeData(const Locale& locale, UErrorCode& status)
     384             : {
     385           0 :     fIntervalPatterns = initHash(status);
     386           0 :     if (U_FAILURE(status)) {
     387           0 :       return;
     388             :     }
     389           0 :     const char *locName = locale.getName();
     390             : 
     391             :     // Get the correct calendar type
     392           0 :     const char * calendarTypeToUse = gGregorianTag; // initial default
     393             :     char         calendarType[ULOC_KEYWORDS_CAPACITY]; // to be filled in with the type to use, if all goes well
     394             :     char         localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY];
     395             :     // obtain a locale that always has the calendar key value that should be used
     396             :     (void)ures_getFunctionalEquivalent(localeWithCalendarKey, ULOC_LOCALE_IDENTIFIER_CAPACITY, NULL,
     397           0 :                                      "calendar", "calendar", locName, NULL, FALSE, &status);
     398           0 :     localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination
     399             :     // now get the calendar key value from that locale
     400             :     int32_t calendarTypeLen = uloc_getKeywordValue(localeWithCalendarKey, "calendar", calendarType,
     401           0 :                                                    ULOC_KEYWORDS_CAPACITY, &status);
     402           0 :     if (U_SUCCESS(status) && calendarTypeLen < ULOC_KEYWORDS_CAPACITY) {
     403           0 :         calendarTypeToUse = calendarType;
     404             :     }
     405           0 :     status = U_ZERO_ERROR;
     406             : 
     407             :     // Instantiate the resource bundles
     408             :     UResourceBundle *rb, *calBundle;
     409           0 :     rb = ures_open(NULL, locName, &status);
     410           0 :     if (U_FAILURE(status)) {
     411           0 :         return;
     412             :     }
     413           0 :     calBundle = ures_getByKeyWithFallback(rb, gCalendarTag, NULL, &status);
     414             : 
     415             : 
     416           0 :     if (U_SUCCESS(status)) {
     417             :         UResourceBundle *calTypeBundle, *itvDtPtnResource;
     418             : 
     419             :         // Get the fallback pattern
     420             :         const UChar* resStr;
     421           0 :         int32_t resStrLen = 0;
     422           0 :         calTypeBundle = ures_getByKeyWithFallback(calBundle, calendarTypeToUse, NULL, &status);
     423             :         itvDtPtnResource = ures_getByKeyWithFallback(calTypeBundle,
     424           0 :                                                      gIntervalDateTimePatternTag, NULL, &status);
     425             :         resStr = ures_getStringByKeyWithFallback(itvDtPtnResource, gFallbackPatternTag,
     426           0 :                                                  &resStrLen, &status);
     427           0 :         if ( U_SUCCESS(status) ) {
     428           0 :             UnicodeString pattern = UnicodeString(TRUE, resStr, resStrLen);
     429           0 :             setFallbackIntervalPattern(pattern, status);
     430             :         }
     431           0 :         ures_close(itvDtPtnResource);
     432           0 :         ures_close(calTypeBundle);
     433             : 
     434             : 
     435             :         // Instantiate the sink
     436           0 :         DateIntervalSink sink(*this, calendarTypeToUse);
     437           0 :         const UnicodeString &calendarTypeToUseUString = sink.getNextCalendarType();
     438             : 
     439             :         // Already loaded calendar types
     440           0 :         Hashtable loadedCalendarTypes(FALSE, status);
     441             : 
     442           0 :         if (U_SUCCESS(status)) {
     443           0 :             while (!calendarTypeToUseUString.isBogus()) {
     444             :                 // Set an error when a loop is detected
     445           0 :                 if (loadedCalendarTypes.geti(calendarTypeToUseUString) == 1) {
     446           0 :                     status = U_INVALID_FORMAT_ERROR;
     447           0 :                     break;
     448             :                 }
     449             : 
     450             :                 // Register the calendar type to avoid loops
     451           0 :                 loadedCalendarTypes.puti(calendarTypeToUseUString, 1, status);
     452           0 :                 if (U_FAILURE(status)) { break; }
     453             : 
     454             :                 // Get the calendar string
     455           0 :                 CharString calTypeBuffer;
     456           0 :                 calTypeBuffer.appendInvariantChars(calendarTypeToUseUString, status);
     457           0 :                 if (U_FAILURE(status)) { break; }
     458           0 :                 const char *calType = calTypeBuffer.data();
     459             : 
     460             :                 // Reset the next calendar type to load.
     461           0 :                 sink.resetNextCalendarType();
     462             : 
     463             :                 // Get all resources for this calendar type
     464           0 :                 ures_getAllItemsWithFallback(calBundle, calType, sink, status);
     465             :             }
     466             :         }
     467             :     }
     468             : 
     469             :     // Close the opened resource bundles
     470           0 :     ures_close(calBundle);
     471           0 :     ures_close(rb);
     472             : }
     473             : 
     474             : void
     475           0 : DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
     476             :                                       UCalendarDateFields lrgDiffCalUnit,
     477             :                                       const UnicodeString& intervalPattern,
     478             :                                       UErrorCode& status) {
     479           0 :     IntervalPatternIndex index = calendarFieldToIntervalIndex(lrgDiffCalUnit,status);
     480           0 :     if ( U_FAILURE(status) ) {
     481           0 :         return;
     482             :     }
     483           0 :     UnicodeString* patternsOfOneSkeleton = (UnicodeString*)(fIntervalPatterns->get(skeleton));
     484           0 :     UBool emptyHash = false;
     485           0 :     if ( patternsOfOneSkeleton == NULL ) {
     486           0 :         patternsOfOneSkeleton = new UnicodeString[kIPI_MAX_INDEX];
     487           0 :         emptyHash = true;
     488             :     }
     489             : 
     490           0 :     patternsOfOneSkeleton[index] = intervalPattern;
     491           0 :     if ( emptyHash == TRUE ) {
     492           0 :         fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status);
     493             :     }
     494             : }
     495             : 
     496             : 
     497             : 
     498             : void
     499           0 : DateIntervalInfo::parseSkeleton(const UnicodeString& skeleton,
     500             :                                 int32_t* skeletonFieldWidth) {
     501           0 :     const int8_t PATTERN_CHAR_BASE = 0x41;
     502             :     int32_t i;
     503           0 :     for ( i = 0; i < skeleton.length(); ++i ) {
     504             :         // it is an ASCII char in skeleton
     505           0 :         int8_t ch = (int8_t)skeleton.charAt(i);
     506           0 :         ++skeletonFieldWidth[ch - PATTERN_CHAR_BASE];
     507             :     }
     508           0 : }
     509             : 
     510             : 
     511             : 
     512             : UBool
     513           0 : DateIntervalInfo::stringNumeric(int32_t fieldWidth, int32_t anotherFieldWidth,
     514             :                                 char patternLetter) {
     515           0 :     if ( patternLetter == 'M' ) {
     516           0 :         if ( (fieldWidth <= 2 && anotherFieldWidth > 2) ||
     517           0 :              (fieldWidth > 2 && anotherFieldWidth <= 2 )) {
     518           0 :             return true;
     519             :         }
     520             :     }
     521           0 :     return false;
     522             : }
     523             : 
     524             : 
     525             : 
     526             : const UnicodeString*
     527           0 : DateIntervalInfo::getBestSkeleton(const UnicodeString& skeleton,
     528             :                                   int8_t& bestMatchDistanceInfo) const {
     529             : #ifdef DTITVINF_DEBUG
     530             :     char result[1000];
     531             :     char result_1[1000];
     532             :     char mesg[2000];
     533             :     skeleton.extract(0,  skeleton.length(), result, "UTF-8");
     534             :     sprintf(mesg, "in getBestSkeleton: skeleton: %s; \n", result);
     535             :     PRINTMESG(mesg)
     536             : #endif
     537             : 
     538             : 
     539             :     int32_t inputSkeletonFieldWidth[] =
     540             :     {
     541             :     //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
     542             :              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     543             :     //   P   Q   R   S   T   U   V   W   X   Y   Z
     544             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0,  0, 0, 0,
     545             :     //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
     546             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     547             :     //   p   q   r   s   t   u   v   w   x   y   z
     548             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
     549           0 :     };
     550             : 
     551             :     int32_t skeletonFieldWidth[] =
     552             :     {
     553             :     //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
     554             :              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     555             :     //   P   Q   R   S   T   U   V   W   X   Y   Z
     556             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0,  0, 0, 0,
     557             :     //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
     558             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
     559             :     //   p   q   r   s   t   u   v   w   x   y   z
     560             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
     561           0 :     };
     562             : 
     563           0 :     const int32_t DIFFERENT_FIELD = 0x1000;
     564           0 :     const int32_t STRING_NUMERIC_DIFFERENCE = 0x100;
     565           0 :     const int32_t BASE = 0x41;
     566           0 :     const UChar CHAR_V = 0x0076;
     567           0 :     const UChar CHAR_Z = 0x007A;
     568             : 
     569             :     // hack for 'v' and 'z'.
     570             :     // resource bundle only have time skeletons ending with 'v',
     571             :     // but not for time skeletons ending with 'z'.
     572           0 :     UBool replaceZWithV = false;
     573           0 :     const UnicodeString* inputSkeleton = &skeleton;
     574           0 :     UnicodeString copySkeleton;
     575           0 :     if ( skeleton.indexOf(CHAR_Z) != -1 ) {
     576           0 :         copySkeleton = skeleton;
     577           0 :         copySkeleton.findAndReplace(UnicodeString(CHAR_Z), UnicodeString(CHAR_V));
     578           0 :         inputSkeleton = &copySkeleton;
     579           0 :         replaceZWithV = true;
     580             :     }
     581             : 
     582           0 :     parseSkeleton(*inputSkeleton, inputSkeletonFieldWidth);
     583           0 :     int32_t bestDistance = MAX_POSITIVE_INT;
     584           0 :     const UnicodeString* bestSkeleton = NULL;
     585             : 
     586             :     // 0 means exact the same skeletons;
     587             :     // 1 means having the same field, but with different length,
     588             :     // 2 means only z/v differs
     589             :     // -1 means having different field.
     590           0 :     bestMatchDistanceInfo = 0;
     591           0 :     int8_t fieldLength = UPRV_LENGTHOF(skeletonFieldWidth);
     592             : 
     593           0 :     int32_t pos = UHASH_FIRST;
     594           0 :     const UHashElement* elem = NULL;
     595           0 :     while ( (elem = fIntervalPatterns->nextElement(pos)) != NULL ) {
     596           0 :         const UHashTok keyTok = elem->key;
     597           0 :         UnicodeString* skeleton = (UnicodeString*)keyTok.pointer;
     598             : #ifdef DTITVINF_DEBUG
     599             :     skeleton->extract(0,  skeleton->length(), result, "UTF-8");
     600             :     sprintf(mesg, "available skeletons: skeleton: %s; \n", result);
     601             :     PRINTMESG(mesg)
     602             : #endif
     603             : 
     604             :         // clear skeleton field width
     605             :         int8_t i;
     606           0 :         for ( i = 0; i < fieldLength; ++i ) {
     607           0 :             skeletonFieldWidth[i] = 0;
     608             :         }
     609           0 :         parseSkeleton(*skeleton, skeletonFieldWidth);
     610             :         // calculate distance
     611           0 :         int32_t distance = 0;
     612           0 :         int8_t fieldDifference = 1;
     613           0 :         for ( i = 0; i < fieldLength; ++i ) {
     614           0 :             int32_t inputFieldWidth = inputSkeletonFieldWidth[i];
     615           0 :             int32_t fieldWidth = skeletonFieldWidth[i];
     616           0 :             if ( inputFieldWidth == fieldWidth ) {
     617           0 :                 continue;
     618             :             }
     619           0 :             if ( inputFieldWidth == 0 ) {
     620           0 :                 fieldDifference = -1;
     621           0 :                 distance += DIFFERENT_FIELD;
     622           0 :             } else if ( fieldWidth == 0 ) {
     623           0 :                 fieldDifference = -1;
     624           0 :                 distance += DIFFERENT_FIELD;
     625           0 :             } else if (stringNumeric(inputFieldWidth, fieldWidth,
     626           0 :                                      (char)(i+BASE) ) ) {
     627           0 :                 distance += STRING_NUMERIC_DIFFERENCE;
     628             :             } else {
     629           0 :                 distance += (inputFieldWidth > fieldWidth) ?
     630             :                             (inputFieldWidth - fieldWidth) :
     631             :                             (fieldWidth - inputFieldWidth);
     632             :             }
     633             :         }
     634           0 :         if ( distance < bestDistance ) {
     635           0 :             bestSkeleton = skeleton;
     636           0 :             bestDistance = distance;
     637           0 :             bestMatchDistanceInfo = fieldDifference;
     638             :         }
     639           0 :         if ( distance == 0 ) {
     640           0 :             bestMatchDistanceInfo = 0;
     641           0 :             break;
     642             :         }
     643             :     }
     644           0 :     if ( replaceZWithV && bestMatchDistanceInfo != -1 ) {
     645           0 :         bestMatchDistanceInfo = 2;
     646             :     }
     647           0 :     return bestSkeleton;
     648             : }
     649             : 
     650             : 
     651             : 
     652             : DateIntervalInfo::IntervalPatternIndex
     653           0 : DateIntervalInfo::calendarFieldToIntervalIndex(UCalendarDateFields field,
     654             :                                                UErrorCode& status) {
     655           0 :     if ( U_FAILURE(status) ) {
     656           0 :         return kIPI_MAX_INDEX;
     657             :     }
     658           0 :     IntervalPatternIndex index = kIPI_MAX_INDEX;
     659           0 :     switch ( field ) {
     660             :       case UCAL_ERA:
     661           0 :         index = kIPI_ERA;
     662           0 :         break;
     663             :       case UCAL_YEAR:
     664           0 :         index = kIPI_YEAR;
     665           0 :         break;
     666             :       case UCAL_MONTH:
     667           0 :         index = kIPI_MONTH;
     668           0 :         break;
     669             :       case UCAL_DATE:
     670             :       case UCAL_DAY_OF_WEEK:
     671             :       //case UCAL_DAY_OF_MONTH:
     672           0 :         index = kIPI_DATE;
     673           0 :         break;
     674             :       case UCAL_AM_PM:
     675           0 :         index = kIPI_AM_PM;
     676           0 :         break;
     677             :       case UCAL_HOUR:
     678             :       case UCAL_HOUR_OF_DAY:
     679           0 :         index = kIPI_HOUR;
     680           0 :         break;
     681             :       case UCAL_MINUTE:
     682           0 :         index = kIPI_MINUTE;
     683           0 :         break;
     684             :       case UCAL_SECOND:
     685           0 :         index = kIPI_SECOND;
     686           0 :         break;
     687             :       default:
     688           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
     689             :     }
     690           0 :     return index;
     691             : }
     692             : 
     693             : 
     694             : 
     695             : void
     696           0 : DateIntervalInfo::deleteHash(Hashtable* hTable)
     697             : {
     698           0 :     if ( hTable == NULL ) {
     699           0 :         return;
     700             :     }
     701           0 :     int32_t pos = UHASH_FIRST;
     702           0 :     const UHashElement* element = NULL;
     703           0 :     while ( (element = hTable->nextElement(pos)) != NULL ) {
     704           0 :         const UHashTok valueTok = element->value;
     705           0 :         const UnicodeString* value = (UnicodeString*)valueTok.pointer;
     706           0 :         delete[] value;
     707             :     }
     708           0 :     delete fIntervalPatterns;
     709             : }
     710             : 
     711             : 
     712             : U_CDECL_BEGIN
     713             : 
     714             : /**
     715             :  * set hash table value comparator
     716             :  *
     717             :  * @param val1  one value in comparison
     718             :  * @param val2  the other value in comparison
     719             :  * @return      TRUE if 2 values are the same, FALSE otherwise
     720             :  */
     721             : static UBool U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2);
     722             : 
     723             : static UBool
     724           0 : U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) {
     725           0 :     const UnicodeString* pattern1 = (UnicodeString*)val1.pointer;
     726           0 :     const UnicodeString* pattern2 = (UnicodeString*)val2.pointer;
     727           0 :     UBool ret = TRUE;
     728             :     int8_t i;
     729           0 :     for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == TRUE; ++i ) {
     730           0 :         ret = (pattern1[i] == pattern2[i]);
     731             :     }
     732           0 :     return ret;
     733             : }
     734             : 
     735             : U_CDECL_END
     736             : 
     737             : 
     738             : Hashtable*
     739           0 : DateIntervalInfo::initHash(UErrorCode& status) {
     740           0 :     if ( U_FAILURE(status) ) {
     741           0 :         return NULL;
     742             :     }
     743             :     Hashtable* hTable;
     744           0 :     if ( (hTable = new Hashtable(FALSE, status)) == NULL ) {
     745           0 :         status = U_MEMORY_ALLOCATION_ERROR;
     746           0 :         return NULL;
     747             :     }
     748           0 :     if ( U_FAILURE(status) ) {
     749           0 :         delete hTable;
     750           0 :         return NULL;
     751             :     }
     752           0 :     hTable->setValueComparator(dtitvinfHashTableValueComparator);
     753           0 :     return hTable;
     754             : }
     755             : 
     756             : 
     757             : void
     758           0 : DateIntervalInfo::copyHash(const Hashtable* source,
     759             :                            Hashtable* target,
     760             :                            UErrorCode& status) {
     761           0 :     if ( U_FAILURE(status) ) {
     762           0 :         return;
     763             :     }
     764           0 :     int32_t pos = UHASH_FIRST;
     765           0 :     const UHashElement* element = NULL;
     766           0 :     if ( source ) {
     767           0 :         while ( (element = source->nextElement(pos)) != NULL ) {
     768           0 :             const UHashTok keyTok = element->key;
     769           0 :             const UnicodeString* key = (UnicodeString*)keyTok.pointer;
     770           0 :             const UHashTok valueTok = element->value;
     771           0 :             const UnicodeString* value = (UnicodeString*)valueTok.pointer;
     772           0 :             UnicodeString* copy = new UnicodeString[kIPI_MAX_INDEX];
     773             :             int8_t i;
     774           0 :             for ( i = 0; i < kIPI_MAX_INDEX; ++i ) {
     775           0 :                 copy[i] = value[i];
     776             :             }
     777           0 :             target->put(UnicodeString(*key), copy, status);
     778           0 :             if ( U_FAILURE(status) ) {
     779           0 :                 return;
     780             :             }
     781             :         }
     782             :     }
     783             : }
     784             : 
     785             : 
     786             : U_NAMESPACE_END
     787             : 
     788             : #endif

Generated by: LCOV version 1.13