Index: icu46/source/common/propname.cpp |
=================================================================== |
--- icu46/source/common/propname.cpp (revision 0) |
+++ icu46/source/common/propname.cpp (revision 0) |
@@ -0,0 +1,752 @@ |
+/* |
+********************************************************************** |
+* Copyright (c) 2002-2009, International Business Machines |
+* Corporation and others. All Rights Reserved. |
+********************************************************************** |
+* Author: Alan Liu |
+* Created: October 30 2002 |
+* Since: ICU 2.4 |
+********************************************************************** |
+*/ |
+#include "propname.h" |
+#include "unicode/uchar.h" |
+#include "unicode/udata.h" |
+#include "umutex.h" |
+#include "cmemory.h" |
+#include "cstring.h" |
+#include "ucln_cmn.h" |
+#include "uarrsort.h" |
+ |
+U_CDECL_BEGIN |
+ |
+/** |
+ * Get the next non-ignorable ASCII character from a property name |
+ * and lowercases it. |
+ * @return ((advance count for the name)<<8)|character |
+ */ |
+static inline int32_t |
+getASCIIPropertyNameChar(const char *name) { |
+ int32_t i; |
+ char c; |
+ |
+ /* Ignore delimiters '-', '_', and ASCII White_Space */ |
+ for(i=0; |
+ (c=name[i++])==0x2d || c==0x5f || |
+ c==0x20 || (0x09<=c && c<=0x0d); |
+ ) {} |
+ |
+ if(c!=0) { |
+ return (i<<8)|(uint8_t)uprv_asciitolower((char)c); |
+ } else { |
+ return i<<8; |
+ } |
+} |
+ |
+/** |
+ * Get the next non-ignorable EBCDIC character from a property name |
+ * and lowercases it. |
+ * @return ((advance count for the name)<<8)|character |
+ */ |
+static inline int32_t |
+getEBCDICPropertyNameChar(const char *name) { |
+ int32_t i; |
+ char c; |
+ |
+ /* Ignore delimiters '-', '_', and EBCDIC White_Space */ |
+ for(i=0; |
+ (c=name[i++])==0x60 || c==0x6d || |
+ c==0x40 || c==0x05 || c==0x15 || c==0x25 || c==0x0b || c==0x0c || c==0x0d; |
+ ) {} |
+ |
+ if(c!=0) { |
+ return (i<<8)|(uint8_t)uprv_ebcdictolower((char)c); |
+ } else { |
+ return i<<8; |
+ } |
+} |
+ |
+/** |
+ * Unicode property names and property value names are compared "loosely". |
+ * |
+ * UCD.html 4.0.1 says: |
+ * For all property names, property value names, and for property values for |
+ * Enumerated, Binary, or Catalog properties, use the following |
+ * loose matching rule: |
+ * |
+ * LM3. Ignore case, whitespace, underscore ('_'), and hyphens. |
+ * |
+ * This function does just that, for (char *) name strings. |
+ * It is almost identical to ucnv_compareNames() but also ignores |
+ * C0 White_Space characters (U+0009..U+000d, and U+0085 on EBCDIC). |
+ * |
+ * @internal |
+ */ |
+ |
+U_CAPI int32_t U_EXPORT2 |
+uprv_compareASCIIPropertyNames(const char *name1, const char *name2) { |
+ int32_t rc, r1, r2; |
+ |
+ for(;;) { |
+ r1=getASCIIPropertyNameChar(name1); |
+ r2=getASCIIPropertyNameChar(name2); |
+ |
+ /* If we reach the ends of both strings then they match */ |
+ if(((r1|r2)&0xff)==0) { |
+ return 0; |
+ } |
+ |
+ /* Compare the lowercased characters */ |
+ if(r1!=r2) { |
+ rc=(r1&0xff)-(r2&0xff); |
+ if(rc!=0) { |
+ return rc; |
+ } |
+ } |
+ |
+ name1+=r1>>8; |
+ name2+=r2>>8; |
+ } |
+} |
+ |
+U_CAPI int32_t U_EXPORT2 |
+uprv_compareEBCDICPropertyNames(const char *name1, const char *name2) { |
+ int32_t rc, r1, r2; |
+ |
+ for(;;) { |
+ r1=getEBCDICPropertyNameChar(name1); |
+ r2=getEBCDICPropertyNameChar(name2); |
+ |
+ /* If we reach the ends of both strings then they match */ |
+ if(((r1|r2)&0xff)==0) { |
+ return 0; |
+ } |
+ |
+ /* Compare the lowercased characters */ |
+ if(r1!=r2) { |
+ rc=(r1&0xff)-(r2&0xff); |
+ if(rc!=0) { |
+ return rc; |
+ } |
+ } |
+ |
+ name1+=r1>>8; |
+ name2+=r2>>8; |
+ } |
+} |
+ |
+U_CDECL_END |
+ |
+U_NAMESPACE_BEGIN |
+ |
+//---------------------------------------------------------------------- |
+// PropertyAliases implementation |
+ |
+const char* |
+PropertyAliases::chooseNameInGroup(Offset offset, |
+ UPropertyNameChoice choice) const { |
+ int32_t c = choice; |
+ if (!offset || c < 0) { |
+ return NULL; |
+ } |
+ const Offset* p = (const Offset*) getPointer(offset); |
+ while (c-- > 0) { |
+ if (*p++ < 0) return NULL; |
+ } |
+ Offset a = *p; |
+ if (a < 0) a = -a; |
+ return (const char*) getPointerNull(a); |
+} |
+ |
+const ValueMap* |
+PropertyAliases::getValueMap(EnumValue prop) const { |
+ NonContiguousEnumToOffset* e2o = (NonContiguousEnumToOffset*) getPointer(enumToValue_offset); |
+ Offset a = e2o->getOffset(prop); |
+ return (const ValueMap*) (a ? getPointerNull(a) : NULL); |
+} |
+ |
+inline const char* |
+PropertyAliases::getPropertyName(EnumValue prop, |
+ UPropertyNameChoice choice) const { |
+ NonContiguousEnumToOffset* e2n = (NonContiguousEnumToOffset*) getPointer(enumToName_offset); |
+ return chooseNameInGroup(e2n->getOffset(prop), choice); |
+} |
+ |
+inline EnumValue |
+PropertyAliases::getPropertyEnum(const char* alias) const { |
+ NameToEnum* n2e = (NameToEnum*) getPointer(nameToEnum_offset); |
+ return n2e->getEnum(alias, *this); |
+} |
+ |
+inline const char* |
+PropertyAliases::getPropertyValueName(EnumValue prop, |
+ EnumValue value, |
+ UPropertyNameChoice choice) const { |
+ const ValueMap* vm = getValueMap(prop); |
+ if (!vm) return NULL; |
+ Offset a; |
+ if (vm->enumToName_offset) { |
+ a = ((EnumToOffset*) getPointer(vm->enumToName_offset))-> |
+ getOffset(value); |
+ } else { |
+ a = ((NonContiguousEnumToOffset*) getPointer(vm->ncEnumToName_offset))-> |
+ getOffset(value); |
+ } |
+ return chooseNameInGroup(a, choice); |
+} |
+ |
+inline EnumValue |
+PropertyAliases::getPropertyValueEnum(EnumValue prop, |
+ const char* alias) const { |
+ const ValueMap* vm = getValueMap(prop); |
+ if (!vm) return UCHAR_INVALID_CODE; |
+ NameToEnum* n2e = (NameToEnum*) getPointer(vm->nameToEnum_offset); |
+ return n2e->getEnum(alias, *this); |
+} |
+ |
+U_NAMESPACE_END |
+U_NAMESPACE_USE |
+ |
+//---------------------------------------------------------------------- |
+// UDataMemory structures |
+ |
+static const PropertyAliases* PNAME = NULL; |
+static UDataMemory* UDATA = NULL; |
+ |
+//---------------------------------------------------------------------- |
+// UDataMemory loading/unloading |
+ |
+/** |
+ * udata callback to verify the zone data. |
+ */ |
+U_CDECL_BEGIN |
+static UBool U_CALLCONV |
+isPNameAcceptable(void* /*context*/, |
+ const char* /*type*/, const char* /*name*/, |
+ const UDataInfo* info) { |
+ return |
+ info->size >= sizeof(UDataInfo) && |
+ info->isBigEndian == U_IS_BIG_ENDIAN && |
+ info->charsetFamily == U_CHARSET_FAMILY && |
+ info->dataFormat[0] == PNAME_SIG_0 && |
+ info->dataFormat[1] == PNAME_SIG_1 && |
+ info->dataFormat[2] == PNAME_SIG_2 && |
+ info->dataFormat[3] == PNAME_SIG_3 && |
+ info->formatVersion[0] == PNAME_FORMAT_VERSION; |
+} |
+ |
+static UBool U_CALLCONV pname_cleanup(void) { |
+ if (UDATA) { |
+ udata_close(UDATA); |
+ UDATA = NULL; |
+ } |
+ PNAME = NULL; |
+ return TRUE; |
+} |
+U_CDECL_END |
+ |
+/** |
+ * Load the property names data. Caller should check that data is |
+ * not loaded BEFORE calling this function. Returns TRUE if the load |
+ * succeeds. |
+ */ |
+static UBool _load() { |
+ UErrorCode ec = U_ZERO_ERROR; |
+ UDataMemory* data = |
+ udata_openChoice(0, PNAME_DATA_TYPE, PNAME_DATA_NAME, |
+ isPNameAcceptable, 0, &ec); |
+ if (U_SUCCESS(ec)) { |
+ umtx_lock(NULL); |
+ if (UDATA == NULL) { |
+ UDATA = data; |
+ PNAME = (const PropertyAliases*) udata_getMemory(UDATA); |
+ ucln_common_registerCleanup(UCLN_COMMON_PNAME, pname_cleanup); |
+ data = NULL; |
+ } |
+ umtx_unlock(NULL); |
+ } |
+ if (data) { |
+ udata_close(data); |
+ } |
+ return PNAME!=NULL; |
+} |
+ |
+/** |
+ * Inline function that expands to code that does a lazy load of the |
+ * property names data. If the data is already loaded, avoids an |
+ * unnecessary function call. If the data is not loaded, call _load() |
+ * to load it, and return TRUE if the load succeeds. |
+ */ |
+static inline UBool load() { |
+ UBool f; |
+ UMTX_CHECK(NULL, (PNAME!=NULL), f); |
+ return f || _load(); |
+} |
+ |
+//---------------------------------------------------------------------- |
+// Public API implementation |
+ |
+// The C API is just a thin wrapper. Each function obtains a pointer |
+// to the singleton PropertyAliases, and calls the appropriate method |
+// on it. If it cannot obtain a pointer, because valid data is not |
+// available, then it returns NULL or UCHAR_INVALID_CODE. |
+ |
+U_CAPI const char* U_EXPORT2 |
+u_getPropertyName(UProperty property, |
+ UPropertyNameChoice nameChoice) { |
+ return load() ? PNAME->getPropertyName(property, nameChoice) |
+ : NULL; |
+} |
+ |
+U_CAPI UProperty U_EXPORT2 |
+u_getPropertyEnum(const char* alias) { |
+ UProperty p = load() ? (UProperty) PNAME->getPropertyEnum(alias) |
+ : UCHAR_INVALID_CODE; |
+ return p; |
+} |
+ |
+U_CAPI const char* U_EXPORT2 |
+u_getPropertyValueName(UProperty property, |
+ int32_t value, |
+ UPropertyNameChoice nameChoice) { |
+ return load() ? PNAME->getPropertyValueName(property, value, nameChoice) |
+ : NULL; |
+} |
+ |
+U_CAPI int32_t U_EXPORT2 |
+u_getPropertyValueEnum(UProperty property, |
+ const char* alias) { |
+ return load() ? PNAME->getPropertyValueEnum(property, alias) |
+ : (int32_t)UCHAR_INVALID_CODE; |
+} |
+ |
+/* data swapping ------------------------------------------------------------ */ |
+ |
+/* |
+ * Sub-structure-swappers use the temp array (which is as large as the |
+ * actual data) for intermediate storage, |
+ * as well as to indicate if a particular structure has been swapped already. |
+ * The temp array is initially reset to all 0. |
+ * pos is the byte offset of the sub-structure in the inBytes/outBytes/temp arrays. |
+ */ |
+ |
+int32_t |
+EnumToOffset::swap(const UDataSwapper *ds, |
+ const uint8_t *inBytes, int32_t length, uint8_t *outBytes, |
+ uint8_t *temp, int32_t pos, |
+ UErrorCode *pErrorCode) { |
+ const EnumToOffset *inMap; |
+ EnumToOffset *outMap, *tempMap; |
+ int32_t size; |
+ |
+ tempMap=(EnumToOffset *)(temp+pos); |
+ if(tempMap->enumStart!=0 || tempMap->enumLimit!=0) { |
+ /* this map was swapped already */ |
+ size=tempMap->getSize(); |
+ return size; |
+ } |
+ |
+ inMap=(const EnumToOffset *)(inBytes+pos); |
+ outMap=(EnumToOffset *)(outBytes+pos); |
+ |
+ tempMap->enumStart=udata_readInt32(ds, inMap->enumStart); |
+ tempMap->enumLimit=udata_readInt32(ds, inMap->enumLimit); |
+ size=tempMap->getSize(); |
+ |
+ if(length>=0) { |
+ if(length<(pos+size)) { |
+ if(length<(int32_t)sizeof(PropertyAliases)) { |
+ udata_printError(ds, "upname_swap(EnumToOffset): too few bytes (%d after header)\n" |
+ " for pnames.icu EnumToOffset{%d..%d} at %d\n", |
+ length, tempMap->enumStart, tempMap->enumLimit, pos); |
+ *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; |
+ return 0; |
+ } |
+ } |
+ |
+ /* swap enumStart and enumLimit */ |
+ ds->swapArray32(ds, inMap, 2*sizeof(EnumValue), outMap, pErrorCode); |
+ |
+ /* swap _offsetArray[] */ |
+ ds->swapArray16(ds, inMap->getOffsetArray(), (tempMap->enumLimit-tempMap->enumStart)*sizeof(Offset), |
+ outMap->getOffsetArray(), pErrorCode); |
+ } |
+ |
+ return size; |
+} |
+ |
+int32_t |
+NonContiguousEnumToOffset::swap(const UDataSwapper *ds, |
+ const uint8_t *inBytes, int32_t length, uint8_t *outBytes, |
+ uint8_t *temp, int32_t pos, |
+ UErrorCode *pErrorCode) { |
+ const NonContiguousEnumToOffset *inMap; |
+ NonContiguousEnumToOffset *outMap, *tempMap; |
+ int32_t size; |
+ |
+ tempMap=(NonContiguousEnumToOffset *)(temp+pos); |
+ if(tempMap->count!=0) { |
+ /* this map was swapped already */ |
+ size=tempMap->getSize(); |
+ return size; |
+ } |
+ |
+ inMap=(const NonContiguousEnumToOffset *)(inBytes+pos); |
+ outMap=(NonContiguousEnumToOffset *)(outBytes+pos); |
+ |
+ tempMap->count=udata_readInt32(ds, inMap->count); |
+ size=tempMap->getSize(); |
+ |
+ if(length>=0) { |
+ if(length<(pos+size)) { |
+ if(length<(int32_t)sizeof(PropertyAliases)) { |
+ udata_printError(ds, "upname_swap(NonContiguousEnumToOffset): too few bytes (%d after header)\n" |
+ " for pnames.icu NonContiguousEnumToOffset[%d] at %d\n", |
+ length, tempMap->count, pos); |
+ *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; |
+ return 0; |
+ } |
+ } |
+ |
+ /* swap count and _enumArray[] */ |
+ length=(1+tempMap->count)*sizeof(EnumValue); |
+ ds->swapArray32(ds, inMap, length, |
+ outMap, pErrorCode); |
+ |
+ /* swap _offsetArray[] */ |
+ pos+=length; |
+ ds->swapArray16(ds, inBytes+pos, tempMap->count*sizeof(Offset), |
+ outBytes+pos, pErrorCode); |
+ } |
+ |
+ return size; |
+} |
+ |
+struct NameAndIndex { |
+ Offset name, index; |
+}; |
+ |
+U_CDECL_BEGIN |
+typedef int32_t U_CALLCONV PropNameCompareFn(const char *name1, const char *name2); |
+ |
+struct CompareContext { |
+ const char *chars; |
+ PropNameCompareFn *propCompare; |
+}; |
+ |
+static int32_t U_CALLCONV |
+upname_compareRows(const void *context, const void *left, const void *right) { |
+ CompareContext *cmp=(CompareContext *)context; |
+ return cmp->propCompare(cmp->chars+((const NameAndIndex *)left)->name, |
+ cmp->chars+((const NameAndIndex *)right)->name); |
+} |
+U_CDECL_END |
+ |
+int32_t |
+NameToEnum::swap(const UDataSwapper *ds, |
+ const uint8_t *inBytes, int32_t length, uint8_t *outBytes, |
+ uint8_t *temp, int32_t pos, |
+ UErrorCode *pErrorCode) { |
+ const NameToEnum *inMap; |
+ NameToEnum *outMap, *tempMap; |
+ |
+ const EnumValue *inEnumArray; |
+ EnumValue *outEnumArray; |
+ |
+ const Offset *inNameArray; |
+ Offset *outNameArray; |
+ |
+ NameAndIndex *sortArray; |
+ CompareContext cmp; |
+ |
+ int32_t i, size, oldIndex; |
+ |
+ tempMap=(NameToEnum *)(temp+pos); |
+ if(tempMap->count!=0) { |
+ /* this map was swapped already */ |
+ size=tempMap->getSize(); |
+ return size; |
+ } |
+ |
+ inMap=(const NameToEnum *)(inBytes+pos); |
+ outMap=(NameToEnum *)(outBytes+pos); |
+ |
+ tempMap->count=udata_readInt32(ds, inMap->count); |
+ size=tempMap->getSize(); |
+ |
+ if(length>=0) { |
+ if(length<(pos+size)) { |
+ if(length<(int32_t)sizeof(PropertyAliases)) { |
+ udata_printError(ds, "upname_swap(NameToEnum): too few bytes (%d after header)\n" |
+ " for pnames.icu NameToEnum[%d] at %d\n", |
+ length, tempMap->count, pos); |
+ *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; |
+ return 0; |
+ } |
+ } |
+ |
+ /* swap count */ |
+ ds->swapArray32(ds, inMap, 4, outMap, pErrorCode); |
+ |
+ inEnumArray=inMap->getEnumArray(); |
+ outEnumArray=outMap->getEnumArray(); |
+ |
+ inNameArray=(const Offset *)(inEnumArray+tempMap->count); |
+ outNameArray=(Offset *)(outEnumArray+tempMap->count); |
+ |
+ if(ds->inCharset==ds->outCharset) { |
+ /* no need to sort, just swap the enum/name arrays */ |
+ ds->swapArray32(ds, inEnumArray, tempMap->count*4, outEnumArray, pErrorCode); |
+ ds->swapArray16(ds, inNameArray, tempMap->count*2, outNameArray, pErrorCode); |
+ return size; |
+ } |
+ |
+ /* |
+ * The name and enum arrays are sorted by names and must be resorted |
+ * if inCharset!=outCharset. |
+ * We use the corresponding part of the temp array to sort an array |
+ * of pairs of name offsets and sorting indexes. |
+ * Then the sorting indexes are used to permutate-swap the name and enum arrays. |
+ * |
+ * The outBytes must already contain the swapped strings. |
+ */ |
+ sortArray=(NameAndIndex *)tempMap->getEnumArray(); |
+ for(i=0; i<tempMap->count; ++i) { |
+ sortArray[i].name=udata_readInt16(ds, inNameArray[i]); |
+ sortArray[i].index=(Offset)i; |
+ } |
+ |
+ /* |
+ * use a stable sort to avoid shuffling of equal strings, |
+ * which makes testing harder |
+ */ |
+ cmp.chars=(const char *)outBytes; |
+ if (ds->outCharset==U_ASCII_FAMILY) { |
+ cmp.propCompare=uprv_compareASCIIPropertyNames; |
+ } |
+ else { |
+ cmp.propCompare=uprv_compareEBCDICPropertyNames; |
+ } |
+ uprv_sortArray(sortArray, tempMap->count, sizeof(NameAndIndex), |
+ upname_compareRows, &cmp, |
+ TRUE, pErrorCode); |
+ if(U_FAILURE(*pErrorCode)) { |
+ udata_printError(ds, "upname_swap(NameToEnum).uprv_sortArray(%d items) failed\n", |
+ tempMap->count); |
+ return 0; |
+ } |
+ |
+ /* copy/swap/permutate _enumArray[] and _nameArray[] */ |
+ if(inEnumArray!=outEnumArray) { |
+ for(i=0; i<tempMap->count; ++i) { |
+ oldIndex=sortArray[i].index; |
+ ds->swapArray32(ds, inEnumArray+oldIndex, 4, outEnumArray+i, pErrorCode); |
+ ds->swapArray16(ds, inNameArray+oldIndex, 2, outNameArray+i, pErrorCode); |
+ } |
+ } else { |
+ /* |
+ * in-place swapping: need to permutate into a temporary array |
+ * and then copy back to not destroy the data |
+ */ |
+ EnumValue *tempEnumArray; |
+ Offset *oldIndexes; |
+ |
+ /* write name offsets directly from sortArray */ |
+ for(i=0; i<tempMap->count; ++i) { |
+ ds->writeUInt16((uint16_t *)outNameArray+i, (uint16_t)sortArray[i].name); |
+ } |
+ |
+ /* |
+ * compress the oldIndexes into a separate array to make space for tempEnumArray |
+ * the tempMap _nameArray becomes oldIndexes[], getting the index |
+ * values from the 2D sortArray[], |
+ * while sortArray=tempMap _enumArray[] becomes tempEnumArray[] |
+ * this saves us allocating more memory |
+ * |
+ * it works because sizeof(NameAndIndex)<=sizeof(EnumValue) |
+ * and because the nameArray[] can be used for oldIndexes[] |
+ */ |
+ tempEnumArray=(EnumValue *)sortArray; |
+ oldIndexes=(Offset *)(sortArray+tempMap->count); |
+ |
+ /* copy sortArray[].index values into oldIndexes[] */ |
+ for(i=0; i<tempMap->count; ++i) { |
+ oldIndexes[i]=sortArray[i].index; |
+ } |
+ |
+ /* permutate inEnumArray[] into tempEnumArray[] */ |
+ for(i=0; i<tempMap->count; ++i) { |
+ ds->swapArray32(ds, inEnumArray+oldIndexes[i], 4, tempEnumArray+i, pErrorCode); |
+ } |
+ |
+ /* copy tempEnumArray[] to outEnumArray[] */ |
+ uprv_memcpy(outEnumArray, tempEnumArray, tempMap->count*4); |
+ } |
+ } |
+ |
+ return size; |
+} |
+ |
+int32_t |
+PropertyAliases::swap(const UDataSwapper *ds, |
+ const uint8_t *inBytes, int32_t length, uint8_t *outBytes, |
+ UErrorCode *pErrorCode) { |
+ const PropertyAliases *inAliases; |
+ PropertyAliases *outAliases; |
+ PropertyAliases aliases; |
+ |
+ const ValueMap *inValueMaps; |
+ ValueMap *outValueMaps; |
+ ValueMap valueMap; |
+ |
+ int32_t i; |
+ |
+ inAliases=(const PropertyAliases *)inBytes; |
+ outAliases=(PropertyAliases *)outBytes; |
+ |
+ /* read the input PropertyAliases - all 16-bit values */ |
+ for(i=0; i<(int32_t)sizeof(PropertyAliases)/2; ++i) { |
+ ((uint16_t *)&aliases)[i]=ds->readUInt16(((const uint16_t *)inBytes)[i]); |
+ } |
+ |
+ if(length>=0) { |
+ if(length<aliases.total_size) { |
+ udata_printError(ds, "upname_swap(): too few bytes (%d after header) for all of pnames.icu\n", |
+ length); |
+ *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; |
+ return 0; |
+ } |
+ |
+ /* copy the data for inaccessible bytes */ |
+ if(inBytes!=outBytes) { |
+ uprv_memcpy(outBytes, inBytes, aliases.total_size); |
+ } |
+ |
+ /* swap the PropertyAliases class fields */ |
+ ds->swapArray16(ds, inAliases, sizeof(PropertyAliases), outAliases, pErrorCode); |
+ |
+ /* swap the name groups */ |
+ ds->swapArray16(ds, inBytes+aliases.nameGroupPool_offset, |
+ aliases.stringPool_offset-aliases.nameGroupPool_offset, |
+ outBytes+aliases.nameGroupPool_offset, pErrorCode); |
+ |
+ /* swap the strings */ |
+ udata_swapInvStringBlock(ds, inBytes+aliases.stringPool_offset, |
+ aliases.total_size-aliases.stringPool_offset, |
+ outBytes+aliases.stringPool_offset, pErrorCode); |
+ |
+ /* |
+ * alloc uint8_t temp[total_size] and reset it |
+ * swap each top-level struct, put at least the count fields into temp |
+ * use subclass-specific swap() functions |
+ * enumerate value maps, for each |
+ * if temp does not have count!=0 yet |
+ * read count, put it into temp |
+ * swap the array(s) |
+ * resort strings in name->enum maps |
+ * swap value maps |
+ */ |
+ LocalMemory<uint8_t> temp; |
+ if(temp.allocateInsteadAndReset(aliases.total_size)==NULL) { |
+ udata_printError(ds, "upname_swap(): unable to allocate temp memory (%d bytes)\n", |
+ aliases.total_size); |
+ *pErrorCode=U_MEMORY_ALLOCATION_ERROR; |
+ return 0; |
+ } |
+ |
+ /* swap properties->name groups map */ |
+ NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes, |
+ temp.getAlias(), aliases.enumToName_offset, pErrorCode); |
+ |
+ /* swap name->properties map */ |
+ NameToEnum::swap(ds, inBytes, length, outBytes, |
+ temp.getAlias(), aliases.nameToEnum_offset, pErrorCode); |
+ |
+ /* swap properties->value maps map */ |
+ NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes, |
+ temp.getAlias(), aliases.enumToValue_offset, pErrorCode); |
+ |
+ /* enumerate all ValueMaps and swap them */ |
+ inValueMaps=(const ValueMap *)(inBytes+aliases.valueMap_offset); |
+ outValueMaps=(ValueMap *)(outBytes+aliases.valueMap_offset); |
+ |
+ for(i=0; i<aliases.valueMap_count; ++i) { |
+ valueMap.enumToName_offset=udata_readInt16(ds, inValueMaps[i].enumToName_offset); |
+ valueMap.ncEnumToName_offset=udata_readInt16(ds, inValueMaps[i].ncEnumToName_offset); |
+ valueMap.nameToEnum_offset=udata_readInt16(ds, inValueMaps[i].nameToEnum_offset); |
+ |
+ if(valueMap.enumToName_offset!=0) { |
+ EnumToOffset::swap(ds, inBytes, length, outBytes, |
+ temp.getAlias(), valueMap.enumToName_offset, |
+ pErrorCode); |
+ } else if(valueMap.ncEnumToName_offset!=0) { |
+ NonContiguousEnumToOffset::swap(ds, inBytes, length, outBytes, |
+ temp.getAlias(), valueMap.ncEnumToName_offset, |
+ pErrorCode); |
+ } |
+ if(valueMap.nameToEnum_offset!=0) { |
+ NameToEnum::swap(ds, inBytes, length, outBytes, |
+ temp.getAlias(), valueMap.nameToEnum_offset, |
+ pErrorCode); |
+ } |
+ } |
+ |
+ /* swap the ValueMaps array itself */ |
+ ds->swapArray16(ds, inValueMaps, aliases.valueMap_count*sizeof(ValueMap), |
+ outValueMaps, pErrorCode); |
+ |
+ /* name groups and strings were swapped above */ |
+ } |
+ |
+ return aliases.total_size; |
+} |
+ |
+U_CAPI int32_t U_EXPORT2 |
+upname_swap(const UDataSwapper *ds, |
+ const void *inData, int32_t length, void *outData, |
+ UErrorCode *pErrorCode) { |
+ const UDataInfo *pInfo; |
+ int32_t headerSize; |
+ |
+ const uint8_t *inBytes; |
+ uint8_t *outBytes; |
+ |
+ /* udata_swapDataHeader checks the arguments */ |
+ headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode); |
+ if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { |
+ return 0; |
+ } |
+ |
+ /* check data format and format version */ |
+ pInfo=(const UDataInfo *)((const char *)inData+4); |
+ if(!( |
+ pInfo->dataFormat[0]==0x70 && /* dataFormat="pnam" */ |
+ pInfo->dataFormat[1]==0x6e && |
+ pInfo->dataFormat[2]==0x61 && |
+ pInfo->dataFormat[3]==0x6d && |
+ pInfo->formatVersion[0]==1 |
+ )) { |
+ udata_printError(ds, "upname_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as pnames.icu\n", |
+ pInfo->dataFormat[0], pInfo->dataFormat[1], |
+ pInfo->dataFormat[2], pInfo->dataFormat[3], |
+ pInfo->formatVersion[0]); |
+ *pErrorCode=U_UNSUPPORTED_ERROR; |
+ return 0; |
+ } |
+ |
+ inBytes=(const uint8_t *)inData+headerSize; |
+ outBytes=(uint8_t *)outData+headerSize; |
+ |
+ if(length>=0) { |
+ length-=headerSize; |
+ if(length<(int32_t)sizeof(PropertyAliases)) { |
+ udata_printError(ds, "upname_swap(): too few bytes (%d after header) for pnames.icu\n", |
+ length); |
+ *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; |
+ return 0; |
+ } |
+ } |
+ |
+ return headerSize+PropertyAliases::swap(ds, inBytes, length, outBytes, pErrorCode); |
+} |
+ |
+//eof |
Property changes on: icu46/source/common/propname.cpp |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |