ICU-12510 resource data enumeration: get array/table objects from ResourceValue, iterate with nested code & functions not by returning nested sinks; use this in DateTimePatternGenerator AllowedHourFormatsSink
X-SVN-Rev: 38655
This commit is contained in:
parent
8f7dd3149c
commit
192500a361
@ -19,6 +19,7 @@ U_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
ResourceValue::~ResourceValue() {}
|
ResourceValue::~ResourceValue() {}
|
||||||
|
|
||||||
|
ResourceSink::~ResourceSink() {}
|
||||||
|
|
||||||
ResourceArraySink::~ResourceArraySink() {}
|
ResourceArraySink::~ResourceArraySink() {}
|
||||||
|
|
||||||
|
@ -27,13 +27,81 @@
|
|||||||
#include "unicode/unistr.h"
|
#include "unicode/unistr.h"
|
||||||
#include "unicode/ures.h"
|
#include "unicode/ures.h"
|
||||||
|
|
||||||
|
struct ResourceData;
|
||||||
|
|
||||||
U_NAMESPACE_BEGIN
|
U_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class ResourceTableSink;
|
class ResourceTableSink;
|
||||||
|
class ResourceValue;
|
||||||
|
|
||||||
// Note: In C++, we use const char * pointers for keys,
|
// Note: In C++, we use const char * pointers for keys,
|
||||||
// rather than an abstraction like Java UResource.Key.
|
// rather than an abstraction like Java UResource.Key.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for iterating over a resource bundle array resource.
|
||||||
|
*/
|
||||||
|
class U_COMMON_API ResourceArray {
|
||||||
|
public:
|
||||||
|
/** Constructs an empty array object. */
|
||||||
|
ResourceArray() : items16(NULL), items32(NULL), length(0) {}
|
||||||
|
|
||||||
|
/** Only for implementation use. @internal */
|
||||||
|
ResourceArray(const uint16_t *i16, const uint32_t *i32, int32_t len) :
|
||||||
|
items16(i16), items32(i32), length(len) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The number of items in the array resource.
|
||||||
|
*/
|
||||||
|
int32_t getSize() const { return length; }
|
||||||
|
/**
|
||||||
|
* @param i Array item index.
|
||||||
|
* @param value Output-only, receives the value of the i'th item.
|
||||||
|
* @return TRUE if i is non-negative and less than getSize().
|
||||||
|
*/
|
||||||
|
UBool getValue(int32_t i, ResourceValue &value) const;
|
||||||
|
|
||||||
|
/** Only for implementation use. @internal */
|
||||||
|
uint32_t internalGetResource(const ResourceData *pResData, int32_t i) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint16_t *items16;
|
||||||
|
const uint32_t *items32;
|
||||||
|
int32_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for iterating over a resource bundle table resource.
|
||||||
|
*/
|
||||||
|
class U_COMMON_API ResourceTable {
|
||||||
|
public:
|
||||||
|
/** Constructs an empty table object. */
|
||||||
|
ResourceTable() : keys16(NULL), keys32(NULL), items16(NULL), items32(NULL), length(0) {}
|
||||||
|
|
||||||
|
/** Only for implementation use. @internal */
|
||||||
|
ResourceTable(const uint16_t *k16, const int32_t *k32,
|
||||||
|
const uint16_t *i16, const uint32_t *i32, int32_t len) :
|
||||||
|
keys16(k16), keys32(k32), items16(i16), items32(i32), length(len) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The number of items in the array resource.
|
||||||
|
*/
|
||||||
|
int32_t getSize() const { return length; }
|
||||||
|
/**
|
||||||
|
* @param i Array item index.
|
||||||
|
* @param key Output-only, receives the key of the i'th item.
|
||||||
|
* @param value Output-only, receives the value of the i'th item.
|
||||||
|
* @return TRUE if i is non-negative and less than getSize().
|
||||||
|
*/
|
||||||
|
UBool getKeyAndValue(int32_t i, const char *&key, ResourceValue &value) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint16_t *keys16;
|
||||||
|
const int32_t *keys32;
|
||||||
|
const uint16_t *items16;
|
||||||
|
const uint32_t *items32;
|
||||||
|
int32_t length;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a resource bundle item's value.
|
* Represents a resource bundle item's value.
|
||||||
* Avoids object creations as much as possible.
|
* Avoids object creations as much as possible.
|
||||||
@ -100,6 +168,73 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual const uint8_t *getBinary(int32_t &length, UErrorCode &errorCode) const = 0;
|
virtual const uint8_t *getBinary(int32_t &length, UErrorCode &errorCode) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets U_RESOURCE_TYPE_MISMATCH if this is not an array resource
|
||||||
|
*/
|
||||||
|
virtual ResourceArray getArray(UErrorCode &errorCode) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets U_RESOURCE_TYPE_MISMATCH if this is not a table resource
|
||||||
|
*/
|
||||||
|
virtual ResourceTable getTable(UErrorCode &errorCode) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this a no-fallback/no-inheritance marker string?
|
||||||
|
* Such a marker is used for
|
||||||
|
* CLDR no-fallback data values of (three empty-set symbols)=={2205, 2205, 2205}
|
||||||
|
* when enumerating tables with fallback from the specific resource bundle to root.
|
||||||
|
*
|
||||||
|
* @return TRUE if this is a no-inheritance marker string
|
||||||
|
*/
|
||||||
|
virtual UBool isNoInheritanceMarker() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the dest strings from the string values in this array resource.
|
||||||
|
*
|
||||||
|
* @return the number of strings in this array resource.
|
||||||
|
* If greater than capacity, then an overflow error is set.
|
||||||
|
*
|
||||||
|
* Sets U_RESOURCE_TYPE_MISMATCH if this is not an array resource
|
||||||
|
* or if any of the array items is not a string
|
||||||
|
*/
|
||||||
|
virtual int32_t getStringArray(UnicodeString *dest, int32_t capacity,
|
||||||
|
UErrorCode &errorCode) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as
|
||||||
|
* <pre>
|
||||||
|
* if (getType() == URES_STRING) {
|
||||||
|
* return new String[] { getString(); }
|
||||||
|
* } else {
|
||||||
|
* return getStringArray();
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* Sets U_RESOURCE_TYPE_MISMATCH if this is
|
||||||
|
* neither a string resource nor an array resource containing strings
|
||||||
|
* @see getString()
|
||||||
|
* @see getStringArray()
|
||||||
|
*/
|
||||||
|
virtual int32_t getStringArrayOrStringAsArray(UnicodeString *dest, int32_t capacity,
|
||||||
|
UErrorCode &errorCode) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as
|
||||||
|
* <pre>
|
||||||
|
* if (getType() == URES_STRING) {
|
||||||
|
* return getString();
|
||||||
|
* } else {
|
||||||
|
* return getStringArray()[0];
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* Sets U_RESOURCE_TYPE_MISMATCH if this is
|
||||||
|
* neither a string resource nor an array resource containing strings
|
||||||
|
* @see getString()
|
||||||
|
* @see getStringArray()
|
||||||
|
*/
|
||||||
|
virtual UnicodeString getStringOrFirstOfArray(UErrorCode &errorCode) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ResourceValue() {}
|
ResourceValue() {}
|
||||||
|
|
||||||
@ -108,6 +243,36 @@ private:
|
|||||||
ResourceValue &operator=(const ResourceValue &); // no assignment operator
|
ResourceValue &operator=(const ResourceValue &); // no assignment operator
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sink for ICU resource bundle contents.
|
||||||
|
*/
|
||||||
|
class U_COMMON_API ResourceSink : public UObject {
|
||||||
|
public:
|
||||||
|
ResourceSink() {}
|
||||||
|
virtual ~ResourceSink();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called once for each bundle (child-parent-...-root).
|
||||||
|
* The value is normally an array or table resource,
|
||||||
|
* and implementations of this method normally iterate over the
|
||||||
|
* tree of resource items stored there.
|
||||||
|
*
|
||||||
|
* @param key The key string of the enumeration-start resource.
|
||||||
|
* Empty if the enumeration starts at the top level of the bundle.
|
||||||
|
* @param value Call getArray() or getTable() as appropriate.
|
||||||
|
* Then reuse for output values from Array and Table getters.
|
||||||
|
* @param noFallback true if the bundle has no parent;
|
||||||
|
* that is, its top-level table has the nofallback attribute,
|
||||||
|
* or it is the root bundle of a locale tree.
|
||||||
|
*/
|
||||||
|
virtual void put(const char *key, ResourceValue &value, UBool noFallback,
|
||||||
|
UErrorCode &errorCode) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ResourceSink(const ResourceSink &); // no copy constructor
|
||||||
|
ResourceSink &operator=(const ResourceSink &); // no assignment operator
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sink for ICU resource array contents.
|
* Sink for ICU resource array contents.
|
||||||
* The base class does nothing.
|
* The base class does nothing.
|
||||||
|
@ -1885,32 +1885,41 @@ ures_getByKeyWithFallback(const UResourceBundle *resB,
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void getAllContainerItemsWithFallback(
|
void getAllItemsWithFallback(
|
||||||
const UResourceBundle *bundle, ResourceDataValue &value,
|
const UResourceBundle *bundle, ResourceDataValue &value,
|
||||||
|
ResourceSink *sink,
|
||||||
ResourceArraySink *arraySink, ResourceTableSink *tableSink,
|
ResourceArraySink *arraySink, ResourceTableSink *tableSink,
|
||||||
UErrorCode &errorCode) {
|
UErrorCode &errorCode) {
|
||||||
if (U_FAILURE(errorCode)) { return; }
|
if (U_FAILURE(errorCode)) { return; }
|
||||||
// We recursively enumerate child-first,
|
// We recursively enumerate child-first,
|
||||||
// only storing parent items in the absence of child items.
|
// only storing parent items in the absence of child items.
|
||||||
// We store a placeholder value for the no-fallback/no-inheritance marker
|
// The sink needs to store a placeholder value for the no-fallback/no-inheritance marker
|
||||||
// to prevent a parent item from being stored.
|
// to prevent a parent item from being stored.
|
||||||
//
|
//
|
||||||
// It would be possible to recursively enumerate parent-first,
|
// It would be possible to recursively enumerate parent-first,
|
||||||
// overriding parent items with child items.
|
// overriding parent items with child items.
|
||||||
// When we see the no-fallback/no-inheritance marker,
|
// When the sink sees the no-fallback/no-inheritance marker,
|
||||||
// then we would remove the parent's item.
|
// then it would remove the parent's item.
|
||||||
// We would deserialize parent values even though they are overridden in a child bundle.
|
// We would deserialize parent values even though they are overridden in a child bundle.
|
||||||
UResType expectedType = arraySink != NULL ? URES_ARRAY : URES_TABLE;
|
|
||||||
if (ures_getType(bundle) == expectedType) {
|
|
||||||
value.pResData = &bundle->fResData;
|
value.pResData = &bundle->fResData;
|
||||||
|
UResourceDataEntry *parentEntry = bundle->fData->fParent;
|
||||||
|
UBool hasParent = parentEntry != NULL && U_SUCCESS(parentEntry->fBogus);
|
||||||
|
UResType expectedType;
|
||||||
|
if (sink != NULL) {
|
||||||
|
expectedType = URES_NONE;
|
||||||
|
value.setResource(bundle->fRes);
|
||||||
|
sink->put(bundle->fKey, value, !hasParent, errorCode);
|
||||||
|
} else {
|
||||||
|
expectedType = arraySink != NULL ? URES_ARRAY : URES_TABLE;
|
||||||
|
if (ures_getType(bundle) == expectedType) {
|
||||||
if (arraySink != NULL) {
|
if (arraySink != NULL) {
|
||||||
ures_getAllArrayItems(&bundle->fResData, bundle->fRes, value, *arraySink, errorCode);
|
ures_getAllArrayItems(&bundle->fResData, bundle->fRes, value, *arraySink, errorCode);
|
||||||
} else /* tableSink != NULL */ {
|
} else /* tableSink != NULL */ {
|
||||||
ures_getAllTableItems(&bundle->fResData, bundle->fRes, value, *tableSink, errorCode);
|
ures_getAllTableItems(&bundle->fResData, bundle->fRes, value, *tableSink, errorCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UResourceDataEntry *entry = bundle->fData->fParent;
|
}
|
||||||
if (entry != NULL && U_SUCCESS(entry->fBogus)) {
|
if (hasParent) {
|
||||||
// We might try to query the sink whether
|
// We might try to query the sink whether
|
||||||
// any fallback from the parent bundle is still possible.
|
// any fallback from the parent bundle is still possible.
|
||||||
|
|
||||||
@ -1921,16 +1930,16 @@ void getAllContainerItemsWithFallback(
|
|||||||
// so that we need not create UResourceBundle objects.
|
// so that we need not create UResourceBundle objects.
|
||||||
UResourceBundle parentBundle;
|
UResourceBundle parentBundle;
|
||||||
ures_initStackObject(&parentBundle);
|
ures_initStackObject(&parentBundle);
|
||||||
parentBundle.fTopLevelData = parentBundle.fData = entry;
|
parentBundle.fTopLevelData = parentBundle.fData = parentEntry;
|
||||||
// TODO: What is the difference between bundle fData and fTopLevelData?
|
// TODO: What is the difference between bundle fData and fTopLevelData?
|
||||||
uprv_memcpy(&parentBundle.fResData, &entry->fData, sizeof(ResourceData));
|
uprv_memcpy(&parentBundle.fResData, &parentEntry->fData, sizeof(ResourceData));
|
||||||
// TODO: Try to replace bundle.fResData with just using bundle.fData->fData.
|
// TODO: Try to replace bundle.fResData with just using bundle.fData->fData.
|
||||||
parentBundle.fHasFallback = !parentBundle.fResData.noFallback;
|
parentBundle.fHasFallback = !parentBundle.fResData.noFallback;
|
||||||
parentBundle.fIsTopLevel = TRUE;
|
parentBundle.fIsTopLevel = TRUE;
|
||||||
parentBundle.fRes = parentBundle.fResData.rootRes;
|
parentBundle.fRes = parentBundle.fResData.rootRes;
|
||||||
parentBundle.fSize = res_countArrayItems(&(parentBundle.fResData), parentBundle.fRes);
|
parentBundle.fSize = res_countArrayItems(&(parentBundle.fResData), parentBundle.fRes);
|
||||||
parentBundle.fIndex = -1;
|
parentBundle.fIndex = -1;
|
||||||
entryIncrease(entry);
|
entryIncrease(parentEntry);
|
||||||
|
|
||||||
// Look up the container item in the parent bundle.
|
// Look up the container item in the parent bundle.
|
||||||
UResourceBundle containerBundle;
|
UResourceBundle containerBundle;
|
||||||
@ -1942,17 +1951,17 @@ void getAllContainerItemsWithFallback(
|
|||||||
rb = ures_getByKeyWithFallback(&parentBundle, bundle->fResPath,
|
rb = ures_getByKeyWithFallback(&parentBundle, bundle->fResPath,
|
||||||
&containerBundle, &errorCode);
|
&containerBundle, &errorCode);
|
||||||
}
|
}
|
||||||
if (U_SUCCESS(errorCode) && ures_getType(rb) == expectedType) {
|
if (U_SUCCESS(errorCode) && (expectedType == URES_NONE || ures_getType(rb) == expectedType)) {
|
||||||
getAllContainerItemsWithFallback(rb, value,
|
getAllItemsWithFallback(rb, value, sink, arraySink, tableSink, errorCode);
|
||||||
arraySink, tableSink, errorCode);
|
|
||||||
}
|
}
|
||||||
ures_close(&containerBundle);
|
ures_close(&containerBundle);
|
||||||
ures_close(&parentBundle);
|
ures_close(&parentBundle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void getAllContainerItemsWithFallback(
|
void getAllItemsWithFallback(
|
||||||
const UResourceBundle *bundle, const char *path,
|
const UResourceBundle *bundle, const char *path,
|
||||||
|
ResourceSink *sink,
|
||||||
ResourceArraySink *arraySink, ResourceTableSink *tableSink,
|
ResourceArraySink *arraySink, ResourceTableSink *tableSink,
|
||||||
UErrorCode &errorCode) {
|
UErrorCode &errorCode) {
|
||||||
if (U_FAILURE(errorCode)) { return; }
|
if (U_FAILURE(errorCode)) { return; }
|
||||||
@ -1973,30 +1982,38 @@ void getAllContainerItemsWithFallback(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sink == NULL) {
|
||||||
UResType expectedType = arraySink != NULL ? URES_ARRAY : URES_TABLE;
|
UResType expectedType = arraySink != NULL ? URES_ARRAY : URES_TABLE;
|
||||||
if (ures_getType(rb) != expectedType) {
|
if (ures_getType(rb) != expectedType) {
|
||||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||||
ures_close(&stackBundle);
|
ures_close(&stackBundle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Get all table items with fallback.
|
// Get all table items with fallback.
|
||||||
ResourceDataValue value;
|
ResourceDataValue value;
|
||||||
getAllContainerItemsWithFallback(rb, value, arraySink, tableSink, errorCode);
|
getAllItemsWithFallback(rb, value, sink, arraySink, tableSink, errorCode);
|
||||||
ures_close(&stackBundle);
|
ures_close(&stackBundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
U_CAPI void U_EXPORT2
|
||||||
|
ures_getAllItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
||||||
|
icu::ResourceSink &sink, UErrorCode &errorCode) {
|
||||||
|
getAllItemsWithFallback(bundle, path, &sink, NULL, NULL, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
U_CAPI void U_EXPORT2
|
U_CAPI void U_EXPORT2
|
||||||
ures_getAllArrayItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
ures_getAllArrayItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
||||||
ResourceArraySink &sink, UErrorCode &errorCode) {
|
ResourceArraySink &sink, UErrorCode &errorCode) {
|
||||||
getAllContainerItemsWithFallback(bundle, path, &sink, NULL, errorCode);
|
getAllItemsWithFallback(bundle, path, NULL, &sink, NULL, errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
U_CAPI void U_EXPORT2
|
U_CAPI void U_EXPORT2
|
||||||
ures_getAllTableItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
ures_getAllTableItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
||||||
ResourceTableSink &sink, UErrorCode &errorCode) {
|
ResourceTableSink &sink, UErrorCode &errorCode) {
|
||||||
getAllContainerItemsWithFallback(bundle, path, NULL, &sink, errorCode);
|
getAllItemsWithFallback(bundle, path, NULL, NULL, &sink, errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, const char* inKey, UResourceBundle *fillIn, UErrorCode *status) {
|
U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, const char* inKey, UResourceBundle *fillIn, UErrorCode *status) {
|
||||||
|
@ -380,6 +380,36 @@ UBool isNoInheritanceMarker(const ResourceData *pResData, Resource res) {
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t getStringArray(const ResourceData *pResData, const icu::ResourceArray &array,
|
||||||
|
icu::UnicodeString *dest, int32_t capacity,
|
||||||
|
UErrorCode &errorCode) {
|
||||||
|
if(U_FAILURE(errorCode)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(dest == NULL ? capacity != 0 : capacity < 0) {
|
||||||
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int32_t length = array.getSize();
|
||||||
|
if(length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(length > capacity) {
|
||||||
|
errorCode = U_BUFFER_OVERFLOW_ERROR;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
for(int32_t i = 0; i < length; ++i) {
|
||||||
|
int32_t sLength;
|
||||||
|
const UChar *s = res_getString(pResData, array.internalGetResource(pResData, i), &sLength);
|
||||||
|
if(s == NULL) {
|
||||||
|
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dest[i].setTo(TRUE, s, sLength);
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
U_CAPI const UChar * U_EXPORT2
|
U_CAPI const UChar * U_EXPORT2
|
||||||
@ -535,6 +565,130 @@ const uint8_t *ResourceDataValue::getBinary(int32_t &length, UErrorCode &errorCo
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResourceArray ResourceDataValue::getArray(UErrorCode &errorCode) const {
|
||||||
|
if(U_FAILURE(errorCode)) {
|
||||||
|
return ResourceArray();
|
||||||
|
}
|
||||||
|
const uint16_t *items16 = NULL;
|
||||||
|
const Resource *items32 = NULL;
|
||||||
|
uint32_t offset=RES_GET_OFFSET(res);
|
||||||
|
int32_t length = 0;
|
||||||
|
switch(RES_GET_TYPE(res)) {
|
||||||
|
case URES_ARRAY:
|
||||||
|
if (offset!=0) { // empty if offset==0
|
||||||
|
items32 = (const Resource *)pResData->pRoot+offset;
|
||||||
|
length = *items32++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case URES_ARRAY16:
|
||||||
|
items16 = pResData->p16BitUnits+offset;
|
||||||
|
length = *items16++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||||
|
return ResourceArray();
|
||||||
|
}
|
||||||
|
return ResourceArray(items16, items32, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceTable ResourceDataValue::getTable(UErrorCode &errorCode) const {
|
||||||
|
if(U_FAILURE(errorCode)) {
|
||||||
|
return ResourceTable();
|
||||||
|
}
|
||||||
|
const uint16_t *keys16 = NULL;
|
||||||
|
const int32_t *keys32 = NULL;
|
||||||
|
const uint16_t *items16 = NULL;
|
||||||
|
const Resource *items32 = NULL;
|
||||||
|
uint32_t offset = RES_GET_OFFSET(res);
|
||||||
|
int32_t length = 0;
|
||||||
|
switch(RES_GET_TYPE(res)) {
|
||||||
|
case URES_TABLE:
|
||||||
|
if (offset != 0) { // empty if offset==0
|
||||||
|
keys16 = (const uint16_t *)(pResData->pRoot+offset);
|
||||||
|
length = *keys16++;
|
||||||
|
items32 = (const Resource *)(keys16+length+(~length&1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case URES_TABLE16:
|
||||||
|
keys16 = pResData->p16BitUnits+offset;
|
||||||
|
length = *keys16++;
|
||||||
|
items16 = keys16 + length;
|
||||||
|
break;
|
||||||
|
case URES_TABLE32:
|
||||||
|
if (offset != 0) { // empty if offset==0
|
||||||
|
keys32 = pResData->pRoot+offset;
|
||||||
|
length = *keys32++;
|
||||||
|
items32 = (const Resource *)keys32 + length;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||||
|
return ResourceTable();
|
||||||
|
}
|
||||||
|
return ResourceTable(keys16, keys32, items16, items32, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
UBool ResourceDataValue::isNoInheritanceMarker() const {
|
||||||
|
return ::isNoInheritanceMarker(pResData, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t ResourceDataValue::getStringArray(UnicodeString *dest, int32_t capacity,
|
||||||
|
UErrorCode &errorCode) const {
|
||||||
|
return ::getStringArray(pResData, getArray(errorCode), dest, capacity, errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t ResourceDataValue::getStringArrayOrStringAsArray(UnicodeString *dest, int32_t capacity,
|
||||||
|
UErrorCode &errorCode) const {
|
||||||
|
if(URES_IS_ARRAY(res)) {
|
||||||
|
return ::getStringArray(pResData, getArray(errorCode), dest, capacity, errorCode);
|
||||||
|
}
|
||||||
|
if(U_FAILURE(errorCode)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(dest == NULL ? capacity != 0 : capacity < 0) {
|
||||||
|
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(capacity < 1) {
|
||||||
|
errorCode = U_BUFFER_OVERFLOW_ERROR;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int32_t sLength;
|
||||||
|
const UChar *s = res_getString(pResData, res, &sLength);
|
||||||
|
if(s != NULL) {
|
||||||
|
dest[0].setTo(TRUE, s, sLength);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnicodeString ResourceDataValue::getStringOrFirstOfArray(UErrorCode &errorCode) const {
|
||||||
|
UnicodeString us;
|
||||||
|
if(U_FAILURE(errorCode)) {
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
int32_t sLength;
|
||||||
|
const UChar *s = res_getString(pResData, res, &sLength);
|
||||||
|
if(s != NULL) {
|
||||||
|
us.setTo(TRUE, s, sLength);
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
ResourceArray array = getArray(errorCode);
|
||||||
|
if(U_FAILURE(errorCode)) {
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
if(array.getSize() > 0) {
|
||||||
|
s = res_getString(pResData, array.internalGetResource(pResData, 0), &sLength);
|
||||||
|
if(s != NULL) {
|
||||||
|
us.setTo(TRUE, s, sLength);
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
|
||||||
static Resource
|
static Resource
|
||||||
@ -673,28 +827,25 @@ ures_getAllTableItems(const ResourceData *pResData, Resource table,
|
|||||||
uint32_t offset = RES_GET_OFFSET(table);
|
uint32_t offset = RES_GET_OFFSET(table);
|
||||||
int32_t length = 0;
|
int32_t length = 0;
|
||||||
switch(RES_GET_TYPE(table)) {
|
switch(RES_GET_TYPE(table)) {
|
||||||
case URES_TABLE: {
|
case URES_TABLE:
|
||||||
if (offset != 0) { /* empty if offset==0 */
|
if (offset != 0) { // empty if offset==0
|
||||||
keys16 = (const uint16_t *)(pResData->pRoot+offset);
|
keys16 = (const uint16_t *)(pResData->pRoot+offset);
|
||||||
length = *keys16++;
|
length = *keys16++;
|
||||||
items32 = (const Resource *)(keys16+length+(~length&1));
|
items32 = (const Resource *)(keys16+length+(~length&1));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case URES_TABLE16:
|
||||||
case URES_TABLE16: {
|
|
||||||
keys16 = pResData->p16BitUnits+offset;
|
keys16 = pResData->p16BitUnits+offset;
|
||||||
length = *keys16++;
|
length = *keys16++;
|
||||||
items16 = keys16 + length;
|
items16 = keys16 + length;
|
||||||
break;
|
break;
|
||||||
}
|
case URES_TABLE32:
|
||||||
case URES_TABLE32: {
|
if (offset != 0) { // empty if offset==0
|
||||||
if (offset != 0) { /* empty if offset==0 */
|
|
||||||
keys32 = pResData->pRoot+offset;
|
keys32 = pResData->pRoot+offset;
|
||||||
length = *keys32++;
|
length = *keys32++;
|
||||||
items32 = (const Resource *)keys32 + length;
|
items32 = (const Resource *)keys32 + length;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||||
return;
|
return;
|
||||||
@ -742,6 +893,27 @@ ures_getAllTableItems(const ResourceData *pResData, Resource table,
|
|||||||
sink.leave(errorCode);
|
sink.leave(errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UBool icu::ResourceTable::getKeyAndValue(int32_t i,
|
||||||
|
const char *&key, icu::ResourceValue &value) const {
|
||||||
|
if(0 <= i && i < length) {
|
||||||
|
icu::ResourceDataValue &rdValue = static_cast<icu::ResourceDataValue &>(value);
|
||||||
|
if (keys16 != NULL) {
|
||||||
|
key = RES_GET_KEY16(rdValue.pResData, keys16[i]);
|
||||||
|
} else {
|
||||||
|
key = RES_GET_KEY32(rdValue.pResData, keys32[i]);
|
||||||
|
}
|
||||||
|
Resource res;
|
||||||
|
if (items16 != NULL) {
|
||||||
|
res = makeResourceFrom16(rdValue.pResData, items16[i]);
|
||||||
|
} else {
|
||||||
|
res = items32[i];
|
||||||
|
}
|
||||||
|
rdValue.setResource(res);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
U_CAPI Resource U_EXPORT2
|
U_CAPI Resource U_EXPORT2
|
||||||
res_getArrayItem(const ResourceData *pResData, Resource array, int32_t indexR) {
|
res_getArrayItem(const ResourceData *pResData, Resource array, int32_t indexR) {
|
||||||
uint32_t offset=RES_GET_OFFSET(array);
|
uint32_t offset=RES_GET_OFFSET(array);
|
||||||
@ -779,18 +951,16 @@ ures_getAllArrayItems(const ResourceData *pResData, Resource array,
|
|||||||
uint32_t offset=RES_GET_OFFSET(array);
|
uint32_t offset=RES_GET_OFFSET(array);
|
||||||
int32_t length = 0;
|
int32_t length = 0;
|
||||||
switch(RES_GET_TYPE(array)) {
|
switch(RES_GET_TYPE(array)) {
|
||||||
case URES_ARRAY: {
|
case URES_ARRAY:
|
||||||
if (offset!=0) { /* empty if offset==0 */
|
if (offset!=0) { // empty if offset==0
|
||||||
items32 = (const Resource *)pResData->pRoot+offset;
|
items32 = (const Resource *)pResData->pRoot+offset;
|
||||||
length = *items32++;
|
length = *items32++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
case URES_ARRAY16:
|
||||||
case URES_ARRAY16: {
|
|
||||||
items16 = pResData->p16BitUnits+offset;
|
items16 = pResData->p16BitUnits+offset;
|
||||||
length = *items16++;
|
length = *items16++;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
errorCode = U_RESOURCE_TYPE_MISMATCH;
|
||||||
return;
|
return;
|
||||||
@ -830,6 +1000,23 @@ ures_getAllArrayItems(const ResourceData *pResData, Resource array,
|
|||||||
sink.leave(errorCode);
|
sink.leave(errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t icu::ResourceArray::internalGetResource(const ResourceData *pResData, int32_t i) const {
|
||||||
|
if (items16 != NULL) {
|
||||||
|
return makeResourceFrom16(pResData, items16[i]);
|
||||||
|
} else {
|
||||||
|
return items32[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UBool icu::ResourceArray::getValue(int32_t i, icu::ResourceValue &value) const {
|
||||||
|
if(0 <= i && i < length) {
|
||||||
|
icu::ResourceDataValue &rdValue = static_cast<icu::ResourceDataValue &>(value);
|
||||||
|
rdValue.setResource(internalGetResource(rdValue.pResData, i));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
U_CFUNC Resource
|
U_CFUNC Resource
|
||||||
res_findResource(const ResourceData *pResData, Resource r, char** path, const char** key) {
|
res_findResource(const ResourceData *pResData, Resource r, char** path, const char** key) {
|
||||||
char *pathP = *path, *nextSepP = *path;
|
char *pathP = *path, *nextSepP = *path;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* Copyright (C) 1999-2015, International Business Machines
|
* Copyright (C) 1999-2016, International Business Machines
|
||||||
* Corporation and others. All Rights Reserved.
|
* Corporation and others. All Rights Reserved.
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* file name: uresdata.h
|
* file name: uresdata.h
|
||||||
@ -379,7 +379,7 @@ enum {
|
|||||||
/*
|
/*
|
||||||
* Structure for a single, memory-mapped ResourceBundle.
|
* Structure for a single, memory-mapped ResourceBundle.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct ResourceData {
|
||||||
UDataMemory *data;
|
UDataMemory *data;
|
||||||
const int32_t *pRoot;
|
const int32_t *pRoot;
|
||||||
const uint16_t *p16BitUnits;
|
const uint16_t *p16BitUnits;
|
||||||
@ -486,6 +486,14 @@ public:
|
|||||||
virtual uint32_t getUInt(UErrorCode &errorCode) const;
|
virtual uint32_t getUInt(UErrorCode &errorCode) const;
|
||||||
virtual const int32_t *getIntVector(int32_t &length, UErrorCode &errorCode) const;
|
virtual const int32_t *getIntVector(int32_t &length, UErrorCode &errorCode) const;
|
||||||
virtual const uint8_t *getBinary(int32_t &length, UErrorCode &errorCode) const;
|
virtual const uint8_t *getBinary(int32_t &length, UErrorCode &errorCode) const;
|
||||||
|
virtual ResourceArray getArray(UErrorCode &errorCode) const;
|
||||||
|
virtual ResourceTable getTable(UErrorCode &errorCode) const;
|
||||||
|
virtual UBool isNoInheritanceMarker() const;
|
||||||
|
virtual int32_t getStringArray(UnicodeString *dest, int32_t capacity,
|
||||||
|
UErrorCode &errorCode) const;
|
||||||
|
virtual int32_t getStringArrayOrStringAsArray(UnicodeString *dest, int32_t capacity,
|
||||||
|
UErrorCode &errorCode) const;
|
||||||
|
virtual UnicodeString getStringOrFirstOfArray(UErrorCode &errorCode) const;
|
||||||
|
|
||||||
const ResourceData *pResData;
|
const ResourceData *pResData;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (C) 2000-2015, International Business Machines
|
* Copyright (C) 2000-2016, International Business Machines
|
||||||
* Corporation and others. All Rights Reserved.
|
* Corporation and others. All Rights Reserved.
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
*/
|
*/
|
||||||
@ -224,6 +224,10 @@ ures_getStringByKeyWithFallback(const UResourceBundle *resB,
|
|||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
U_CAPI void U_EXPORT2
|
||||||
|
ures_getAllItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
||||||
|
icu::ResourceSink &sink, UErrorCode &errorCode);
|
||||||
|
|
||||||
U_CAPI void U_EXPORT2
|
U_CAPI void U_EXPORT2
|
||||||
ures_getAllArrayItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
ures_getAllArrayItemsWithFallback(const UResourceBundle *bundle, const char *path,
|
||||||
icu::ResourceArraySink &sink, UErrorCode &errorCode);
|
icu::ResourceArraySink &sink, UErrorCode &errorCode);
|
||||||
|
@ -434,79 +434,48 @@ DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct AllowedHourFormatsSink : public ResourceTableSink {
|
struct AllowedHourFormatsSink : public ResourceSink {
|
||||||
// Initialize sub-sinks.
|
// Initialize sub-sinks.
|
||||||
AllowedHourFormatsSink() : localeSink(*this), allowedListSink(*this) {}
|
AllowedHourFormatsSink() {}
|
||||||
virtual ~AllowedHourFormatsSink();
|
virtual ~AllowedHourFormatsSink();
|
||||||
|
|
||||||
// Entry point.
|
virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
|
||||||
virtual ResourceTableSink *getOrCreateTableSink(const char *key, UErrorCode &status) {
|
UErrorCode &errorCode) {
|
||||||
if (U_FAILURE(status)) { return NULL; }
|
ResourceTable timeData = value.getTable(errorCode);
|
||||||
|
if (U_FAILURE(errorCode)) { return; }
|
||||||
locale = key;
|
for (int32_t i = 0; timeData.getKeyAndValue(i, key, value); ++i) {
|
||||||
return &localeSink;
|
const char *regionOrLocale = key;
|
||||||
}
|
ResourceTable formatList = value.getTable(errorCode);
|
||||||
|
if (U_FAILURE(errorCode)) { return; }
|
||||||
struct LocaleSink : public ResourceTableSink {
|
for (int32_t j = 0; formatList.getKeyAndValue(j, key, value); ++j) {
|
||||||
AllowedHourFormatsSink &outer;
|
if (uprv_strcmp(key, "allowed") == 0) { // Ignore "preferred" list.
|
||||||
LocaleSink(AllowedHourFormatsSink &outer) : outer(outer) {}
|
LocalArray<int32_t> list;
|
||||||
virtual ~LocaleSink();
|
int32_t length;
|
||||||
|
if (value.getType() == URES_STRING) {
|
||||||
virtual void put(const char *key, const ResourceValue &value, UErrorCode &status) {
|
list.adoptInsteadAndCheckErrorCode(
|
||||||
if (U_FAILURE(status)) { return; }
|
static_cast<int32_t *>(uprv_malloc(2 * sizeof(int32_t))), errorCode);
|
||||||
|
if (U_FAILURE(errorCode)) { return; }
|
||||||
if (uprv_strcmp(key, "allowed") == 0) {
|
list[0] = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));
|
||||||
outer.allowedFormats = static_cast<int32_t *>(uprv_malloc(2 * sizeof(int32_t)));
|
length = 1;
|
||||||
outer.allowedFormatsLength = 1;
|
} else {
|
||||||
if (outer.allowedFormats == NULL) {
|
ResourceArray allowedFormats = value.getArray(errorCode);
|
||||||
status = U_MEMORY_ALLOCATION_ERROR;
|
length = allowedFormats.getSize();
|
||||||
return;
|
list.adoptInsteadAndCheckErrorCode(
|
||||||
}
|
static_cast<int32_t *>(uprv_malloc((length + 1) * sizeof(int32_t))), errorCode);
|
||||||
outer.allowedFormats[0] = outer.getHourFormatFromUnicodeString(
|
if (U_FAILURE(errorCode)) { return; }
|
||||||
value.getUnicodeString(status));
|
for (int32_t k = 0; k < length; ++k) {
|
||||||
|
allowedFormats.getValue(k, value);
|
||||||
|
list[k] = getHourFormatFromUnicodeString(value.getUnicodeString(errorCode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
list[length] = ALLOWED_HOUR_FORMAT_UNKNOWN;
|
||||||
virtual ResourceArraySink *getOrCreateArraySink(const char *key, UErrorCode &status) {
|
uhash_put(localeToAllowedHourFormatsMap,
|
||||||
if (U_SUCCESS(status) && uprv_strcmp(key, "allowed") == 0) {
|
const_cast<char *>(regionOrLocale), list.orphan(), &errorCode);
|
||||||
return &outer.allowedListSink;
|
if (U_FAILURE(errorCode)) { return; }
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void leave(UErrorCode &status) {
|
|
||||||
if (U_FAILURE(status) || outer.allowedFormats == NULL) { return; }
|
|
||||||
|
|
||||||
outer.allowedFormats[outer.allowedFormatsLength] = ALLOWED_HOUR_FORMAT_UNKNOWN;
|
|
||||||
uhash_put(localeToAllowedHourFormatsMap, const_cast<char *>(outer.locale), outer.allowedFormats, &status);
|
|
||||||
outer.allowedFormats = NULL;
|
|
||||||
}
|
|
||||||
} localeSink;
|
|
||||||
|
|
||||||
struct AllowedListSink : public ResourceArraySink {
|
|
||||||
AllowedHourFormatsSink &outer;
|
|
||||||
AllowedListSink(AllowedHourFormatsSink &outer) : outer(outer) {}
|
|
||||||
virtual ~AllowedListSink();
|
|
||||||
|
|
||||||
virtual void enter(int32_t size, UErrorCode &status) {
|
|
||||||
if (U_FAILURE(status)) { return; }
|
|
||||||
outer.allowedFormats = static_cast<int32_t *>(uprv_malloc((size + 1) * sizeof(int32_t)));
|
|
||||||
outer.allowedFormatsLength = size;
|
|
||||||
if (outer.allowedFormats == NULL) {
|
|
||||||
status = U_MEMORY_ALLOCATION_ERROR;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void put(int32_t index, const ResourceValue &value, UErrorCode &status) {
|
|
||||||
if (U_FAILURE(status)) { return; }
|
|
||||||
|
|
||||||
outer.allowedFormats[index] = outer.getHourFormatFromUnicodeString(
|
|
||||||
value.getUnicodeString(status));
|
|
||||||
}
|
}
|
||||||
} allowedListSink;
|
|
||||||
|
|
||||||
const char *locale;
|
|
||||||
int32_t *allowedFormats;
|
|
||||||
int32_t allowedFormatsLength;
|
|
||||||
|
|
||||||
AllowedHourFormat getHourFormatFromUnicodeString(UnicodeString s) {
|
AllowedHourFormat getHourFormatFromUnicodeString(UnicodeString s) {
|
||||||
if (s.length() == 1) {
|
if (s.length() == 1) {
|
||||||
@ -526,8 +495,6 @@ struct AllowedHourFormatsSink : public ResourceTableSink {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
AllowedHourFormatsSink::~AllowedHourFormatsSink() {}
|
AllowedHourFormatsSink::~AllowedHourFormatsSink() {}
|
||||||
AllowedHourFormatsSink::LocaleSink::~LocaleSink() {}
|
|
||||||
AllowedHourFormatsSink::AllowedListSink::~AllowedListSink() {}
|
|
||||||
|
|
||||||
void DateTimePatternGenerator::loadAllowedHourFormatsData(UErrorCode &status) {
|
void DateTimePatternGenerator::loadAllowedHourFormatsData(UErrorCode &status) {
|
||||||
if (U_FAILURE(status)) { return; }
|
if (U_FAILURE(status)) { return; }
|
||||||
@ -543,7 +510,7 @@ void DateTimePatternGenerator::loadAllowedHourFormatsData(UErrorCode &status) {
|
|||||||
// into the hashmap, store 6 single-value sub-arrays right at the beginning of the
|
// into the hashmap, store 6 single-value sub-arrays right at the beginning of the
|
||||||
// vector (at index enum*2) for easy data sharing, copy sub-arrays into runtime
|
// vector (at index enum*2) for easy data sharing, copy sub-arrays into runtime
|
||||||
// object. Remember to clean up the vector, too.
|
// object. Remember to clean up the vector, too.
|
||||||
ures_getAllTableItemsWithFallback(rb.getAlias(), "timeData", sink, status);
|
ures_getAllItemsWithFallback(rb.getAlias(), "timeData", sink, status);
|
||||||
|
|
||||||
ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup);
|
ucln_i18n_registerCleanup(UCLN_I18N_ALLOWED_HOUR_FORMATS, allowedHourFormatsCleanup);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user