summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp')
-rw-r--r--Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp1225
1 files changed, 1225 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp b/Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp
new file mode 100644
index 00000000000..84294a62ee0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/tools/genpname/genpname.cpp
@@ -0,0 +1,1225 @@
+/*
+**********************************************************************
+* Copyright (C) 2002-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 10/11/02 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "unicode/uclean.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "filestrm.h"
+#include "uarrsort.h"
+#include "unewdata.h"
+#include "uoptions.h"
+#include "uprops.h"
+#include "propname.h"
+#include "uassert.h"
+
+#include <stdio.h>
+
+U_NAMESPACE_USE
+
+// TODO: Clean up and comment this code.
+
+//----------------------------------------------------------------------
+// BEGIN DATA
+//
+// This is the raw data to be output. We define the data structure,
+// then include a machine-generated header that contains the actual
+// data.
+
+#include "unicode/uchar.h"
+#include "unicode/uscript.h"
+#include "unicode/unorm.h"
+
+class AliasName {
+public:
+ const char* str;
+ int32_t index;
+
+ AliasName(const char* str, int32_t index);
+
+ int compare(const AliasName& other) const;
+
+ UBool operator==(const AliasName& other) const {
+ return compare(other) == 0;
+ }
+
+ UBool operator!=(const AliasName& other) const {
+ return compare(other) != 0;
+ }
+};
+
+AliasName::AliasName(const char* _str,
+ int32_t _index) :
+ str(_str),
+ index(_index)
+{
+}
+
+int AliasName::compare(const AliasName& other) const {
+ return uprv_comparePropertyNames(str, other.str);
+}
+
+class Alias {
+public:
+ int32_t enumValue;
+ int32_t nameGroupIndex;
+
+ Alias(int32_t enumValue,
+ int32_t nameGroupIndex);
+
+ int32_t getUniqueNames(int32_t* nameGroupIndices) const;
+};
+
+Alias::Alias(int32_t anEnumValue,
+ int32_t aNameGroupIndex) :
+ enumValue(anEnumValue),
+ nameGroupIndex(aNameGroupIndex)
+{
+}
+
+class Property : public Alias {
+public:
+ int32_t valueCount;
+ const Alias* valueList;
+
+ Property(int32_t enumValue,
+ int32_t nameGroupIndex,
+ int32_t valueCount,
+ const Alias* valueList);
+};
+
+Property::Property(int32_t _enumValue,
+ int32_t _nameGroupIndex,
+ int32_t _valueCount,
+ const Alias* _valueList) :
+ Alias(_enumValue, _nameGroupIndex),
+ valueCount(_valueCount),
+ valueList(_valueList)
+{
+}
+
+// *** Include the data header ***
+#include "data.h"
+
+/* return a list of unique names, not including "", for this property
+ * @param stringIndices array of at least MAX_NAMES_PER_GROUP
+ * elements, will be filled with indices into STRING_TABLE
+ * @return number of indices, >= 1
+ */
+int32_t Alias::getUniqueNames(int32_t* stringIndices) const {
+ int32_t count = 0;
+ int32_t i = nameGroupIndex;
+ UBool done = FALSE;
+ while (!done) {
+ int32_t j = NAME_GROUP[i++];
+ if (j < 0) {
+ done = TRUE;
+ j = -j;
+ }
+ if (j == 0) continue; // omit "" entries
+ UBool dupe = FALSE;
+ for (int32_t k=0; k<count; ++k) {
+ if (stringIndices[k] == j) {
+ dupe = TRUE;
+ break;
+ }
+ // also do a string check for things like "age|Age"
+ if (STRING_TABLE[stringIndices[k]] == STRING_TABLE[j]) {
+ //printf("Found dupe %s|%s\n",
+ // STRING_TABLE[stringIndices[k]].str,
+ // STRING_TABLE[j].str);
+ dupe = TRUE;
+ break;
+ }
+ }
+ if (dupe) continue; // omit duplicates
+ stringIndices[count++] = j;
+ }
+ return count;
+}
+
+// END DATA
+//----------------------------------------------------------------------
+
+#define MALLOC(type, count) \
+ (type*) uprv_malloc(sizeof(type) * count)
+
+void die(const char* msg) {
+ fprintf(stderr, "Error: %s\n", msg);
+ exit(1);
+}
+
+//----------------------------------------------------------------------
+
+/**
+ * A list of Alias objects.
+ */
+class AliasList {
+public:
+ virtual ~AliasList();
+ virtual const Alias& operator[](int32_t i) const = 0;
+ virtual int32_t count() const = 0;
+};
+
+AliasList::~AliasList() {}
+
+/**
+ * A single array.
+ */
+class AliasArrayList : public AliasList {
+ const Alias* a;
+ int32_t n;
+public:
+ AliasArrayList(const Alias* _a, int32_t _n) {
+ a = _a;
+ n = _n;
+ }
+ virtual const Alias& operator[](int32_t i) const {
+ return a[i];
+ }
+ virtual int32_t count() const {
+ return n;
+ }
+};
+
+/**
+ * A single array.
+ */
+class PropertyArrayList : public AliasList {
+ const Property* a;
+ int32_t n;
+public:
+ PropertyArrayList(const Property* _a, int32_t _n) {
+ a = _a;
+ n = _n;
+ }
+ virtual const Alias& operator[](int32_t i) const {
+ return a[i];
+ }
+ virtual int32_t count() const {
+ return n;
+ }
+};
+
+//----------------------------------------------------------------------
+
+/**
+ * An element in a name index. It maps a name (given by index) into
+ * an enum value.
+ */
+class NameToEnumEntry {
+public:
+ int32_t nameIndex;
+ int32_t enumValue;
+ NameToEnumEntry(int32_t a, int32_t b) { nameIndex=a; enumValue=b; }
+};
+
+// Sort function for NameToEnumEntry (sort by name)
+U_CFUNC int32_t
+compareNameToEnumEntry(const void * /*context*/, const void* e1, const void* e2) {
+ return
+ STRING_TABLE[((NameToEnumEntry*)e1)->nameIndex].
+ compare(STRING_TABLE[((NameToEnumEntry*)e2)->nameIndex]);
+}
+
+//----------------------------------------------------------------------
+
+/**
+ * An element in an enum index. It maps an enum into a name group entry
+ * (given by index).
+ */
+class EnumToNameGroupEntry {
+public:
+ int32_t enumValue;
+ int32_t nameGroupIndex;
+ EnumToNameGroupEntry(int32_t a, int32_t b) { enumValue=a; nameGroupIndex=b; }
+
+ // are enumValues contiguous for count entries starting with this one?
+ // ***!!!*** we assume we are in an array and look at neighbors ***!!!***
+ UBool isContiguous(int32_t count) const {
+ const EnumToNameGroupEntry* p = this;
+ for (int32_t i=1; i<count; ++i) {
+ if (p[i].enumValue != (this->enumValue + i)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+};
+
+// Sort function for EnumToNameGroupEntry (sort by name index)
+U_CFUNC int32_t
+compareEnumToNameGroupEntry(const void * /*context*/, const void* e1, const void* e2) {
+ return ((EnumToNameGroupEntry*)e1)->enumValue - ((EnumToNameGroupEntry*)e2)->enumValue;
+}
+
+//----------------------------------------------------------------------
+
+/**
+ * An element in the map from enumerated property enums to value maps.
+ */
+class EnumToValueEntry {
+public:
+ int32_t enumValue;
+ EnumToNameGroupEntry* enumToName;
+ int32_t enumToName_count;
+ NameToEnumEntry* nameToEnum;
+ int32_t nameToEnum_count;
+
+ // are enumValues contiguous for count entries starting with this one?
+ // ***!!!*** we assume we are in an array and look at neighbors ***!!!***
+ UBool isContiguous(int32_t count) const {
+ const EnumToValueEntry* p = this;
+ for (int32_t i=1; i<count; ++i) {
+ if (p[i].enumValue != (this->enumValue + i)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+};
+
+// Sort function for EnumToValueEntry (sort by enum)
+U_CFUNC int32_t
+compareEnumToValueEntry(const void * /*context*/, const void* e1, const void* e2) {
+ return ((EnumToValueEntry*)e1)->enumValue - ((EnumToValueEntry*)e2)->enumValue;
+}
+
+//----------------------------------------------------------------------
+// BEGIN Builder
+
+#define IS_VALID_OFFSET(x) (((x)>=0)&&((x)<=MAX_OFFSET))
+
+class Builder {
+ // header:
+ PropertyAliases header;
+
+ // 0:
+ NonContiguousEnumToOffset* enumToName;
+ int32_t enumToName_size;
+ Offset enumToName_offset;
+
+ // 1: (deleted)
+
+ // 2:
+ NameToEnum* nameToEnum;
+ int32_t nameToEnum_size;
+ Offset nameToEnum_offset;
+
+ // 3:
+ NonContiguousEnumToOffset* enumToValue;
+ int32_t enumToValue_size;
+ Offset enumToValue_offset;
+
+ // 4:
+ ValueMap* valueMap;
+ int32_t valueMap_size;
+ int32_t valueMap_count;
+ Offset valueMap_offset;
+
+ // for any i, one of valueEnumToName[i] or valueNCEnumToName[i] is
+ // NULL and one is not. valueEnumToName_size[i] is the size of
+ // the non-NULL one. i=0..valueMapCount-1
+ // 5a:
+ EnumToOffset** valueEnumToName;
+ // 5b:
+ NonContiguousEnumToOffset** valueNCEnumToName;
+ int32_t* valueEnumToName_size;
+ Offset* valueEnumToName_offset;
+ // 6:
+ // arrays of valueMap_count pointers, sizes, & offsets
+ NameToEnum** valueNameToEnum;
+ int32_t* valueNameToEnum_size;
+ Offset* valueNameToEnum_offset;
+
+ // 98:
+ Offset* nameGroupPool;
+ int32_t nameGroupPool_count;
+ int32_t nameGroupPool_size;
+ Offset nameGroupPool_offset;
+
+ // 99:
+ char* stringPool;
+ int32_t stringPool_count;
+ int32_t stringPool_size;
+ Offset stringPool_offset;
+ Offset* stringPool_offsetArray; // relative to stringPool
+
+ int32_t total_size; // size of everything
+
+ int32_t debug;
+
+public:
+
+ Builder(int32_t debugLevel);
+ ~Builder();
+
+ void buildTopLevelProperties(const NameToEnumEntry* propName,
+ int32_t propNameCount,
+ const EnumToNameGroupEntry* propEnum,
+ int32_t propEnumCount);
+
+ void buildValues(const EnumToValueEntry* e2v,
+ int32_t count);
+
+ void buildStringPool(const AliasName* propertyNames,
+ int32_t propertyNameCount,
+ const int32_t* nameGroupIndices,
+ int32_t nameGroupIndicesCount);
+
+ void fixup();
+
+ int8_t* createData(int32_t& length) const;
+
+private:
+
+ static EnumToOffset* buildEnumToOffset(const EnumToNameGroupEntry* e2ng,
+ int32_t count,
+ int32_t& size);
+ static NonContiguousEnumToOffset*
+ buildNCEnumToNameGroup(const EnumToNameGroupEntry* e2ng,
+ int32_t count,
+ int32_t& size);
+
+ static NonContiguousEnumToOffset*
+ buildNCEnumToValue(const EnumToValueEntry* e2v,
+ int32_t count,
+ int32_t& size);
+
+ static NameToEnum* buildNameToEnum(const NameToEnumEntry* nameToEnum,
+ int32_t count,
+ int32_t& size);
+
+ Offset stringIndexToOffset(int32_t index, UBool allowNeg=FALSE) const;
+ void fixupNameToEnum(NameToEnum* n);
+ void fixupEnumToNameGroup(EnumToOffset* e2ng);
+ void fixupNCEnumToNameGroup(NonContiguousEnumToOffset* e2ng);
+
+ void computeOffsets();
+ void fixupStringPoolOffsets();
+ void fixupNameGroupPoolOffsets();
+ void fixupMiscellaneousOffsets();
+
+ static int32_t align(int32_t a);
+ static void erase(void* p, int32_t size);
+};
+
+Builder::Builder(int32_t debugLevel) {
+ debug = debugLevel;
+ enumToName = 0;
+ nameToEnum = 0;
+ enumToValue = 0;
+ valueMap_count = 0;
+ valueMap = 0;
+ valueEnumToName = 0;
+ valueNCEnumToName = 0;
+ valueEnumToName_size = 0;
+ valueEnumToName_offset = 0;
+ valueNameToEnum = 0;
+ valueNameToEnum_size = 0;
+ valueNameToEnum_offset = 0;
+ nameGroupPool = 0;
+ stringPool = 0;
+ stringPool_offsetArray = 0;
+}
+
+Builder::~Builder() {
+ uprv_free(enumToName);
+ uprv_free(nameToEnum);
+ uprv_free(enumToValue);
+ uprv_free(valueMap);
+ for (int32_t i=0; i<valueMap_count; ++i) {
+ uprv_free(valueEnumToName[i]);
+ uprv_free(valueNCEnumToName[i]);
+ uprv_free(valueNameToEnum[i]);
+ }
+ uprv_free(valueEnumToName);
+ uprv_free(valueNCEnumToName);
+ uprv_free(valueEnumToName_size);
+ uprv_free(valueEnumToName_offset);
+ uprv_free(valueNameToEnum);
+ uprv_free(valueNameToEnum_size);
+ uprv_free(valueNameToEnum_offset);
+ uprv_free(nameGroupPool);
+ uprv_free(stringPool);
+ uprv_free(stringPool_offsetArray);
+}
+
+int32_t Builder::align(int32_t a) {
+ U_ASSERT(a >= 0);
+ int32_t k = a % sizeof(int32_t);
+ if (k == 0) {
+ return a;
+ }
+ a += sizeof(int32_t) - k;
+ return a;
+}
+
+void Builder::erase(void* p, int32_t size) {
+ U_ASSERT(size >= 0);
+ int8_t* q = (int8_t*) p;
+ while (size--) {
+ *q++ = 0;
+ }
+}
+
+EnumToOffset* Builder::buildEnumToOffset(const EnumToNameGroupEntry* e2ng,
+ int32_t count,
+ int32_t& size) {
+ U_ASSERT(e2ng->isContiguous(count));
+ size = align(EnumToOffset::getSize(count));
+ EnumToOffset* result = (EnumToOffset*) uprv_malloc(size);
+ erase(result, size);
+ result->enumStart = e2ng->enumValue;
+ result->enumLimit = e2ng->enumValue + count;
+ Offset* p = result->getOffsetArray();
+ for (int32_t i=0; i<count; ++i) {
+ // set these to NGI index values
+ // fix them up to NGI offset values
+ U_ASSERT(IS_VALID_OFFSET(e2ng[i].nameGroupIndex));
+ p[i] = (Offset) e2ng[i].nameGroupIndex; // FIXUP later
+ }
+ return result;
+}
+
+NonContiguousEnumToOffset*
+Builder::buildNCEnumToNameGroup(const EnumToNameGroupEntry* e2ng,
+ int32_t count,
+ int32_t& size) {
+ U_ASSERT(!e2ng->isContiguous(count));
+ size = align(NonContiguousEnumToOffset::getSize(count));
+ NonContiguousEnumToOffset* nc = (NonContiguousEnumToOffset*) uprv_malloc(size);
+ erase(nc, size);
+ nc->count = count;
+ EnumValue* e = nc->getEnumArray();
+ Offset* p = nc->getOffsetArray();
+ for (int32_t i=0; i<count; ++i) {
+ // set these to NGI index values
+ // fix them up to NGI offset values
+ e[i] = e2ng[i].enumValue;
+ U_ASSERT(IS_VALID_OFFSET(e2ng[i].nameGroupIndex));
+ p[i] = (Offset) e2ng[i].nameGroupIndex; // FIXUP later
+ }
+ return nc;
+}
+
+NonContiguousEnumToOffset*
+Builder::buildNCEnumToValue(const EnumToValueEntry* e2v,
+ int32_t count,
+ int32_t& size) {
+ U_ASSERT(!e2v->isContiguous(count));
+ size = align(NonContiguousEnumToOffset::getSize(count));
+ NonContiguousEnumToOffset* result = (NonContiguousEnumToOffset*) uprv_malloc(size);
+ erase(result, size);
+ result->count = count;
+ EnumValue* e = result->getEnumArray();
+ for (int32_t i=0; i<count; ++i) {
+ e[i] = e2v[i].enumValue;
+ // offset must be set later
+ }
+ return result;
+}
+
+/**
+ * Given an index into the string pool, return an offset. computeOffsets()
+ * must have been called already. If allowNegative is true, allow negatives
+ * and preserve their sign.
+ */
+Offset Builder::stringIndexToOffset(int32_t index, UBool allowNegative) const {
+ // Index 0 is ""; we turn this into an Offset of zero
+ if (index == 0) return 0;
+ if (index < 0) {
+ if (allowNegative) {
+ return -Builder::stringIndexToOffset(-index);
+ } else {
+ die("Negative string pool index");
+ }
+ } else {
+ if (index >= stringPool_count) {
+ die("String pool index too large");
+ }
+ Offset result = stringPool_offset + stringPool_offsetArray[index];
+ U_ASSERT(result >= 0 && result < total_size);
+ return result;
+ }
+ return 0; // never executed; make compiler happy
+}
+
+NameToEnum* Builder::buildNameToEnum(const NameToEnumEntry* nameToEnum,
+ int32_t count,
+ int32_t& size) {
+ size = align(NameToEnum::getSize(count));
+ NameToEnum* n2e = (NameToEnum*) uprv_malloc(size);
+ erase(n2e, size);
+ n2e->count = count;
+ Offset* p = n2e->getNameArray();
+ EnumValue* e = n2e->getEnumArray();
+ for (int32_t i=0; i<count; ++i) {
+ // set these to SP index values
+ // fix them up to SP offset values
+ U_ASSERT(IS_VALID_OFFSET(nameToEnum[i].nameIndex));
+ p[i] = (Offset) nameToEnum[i].nameIndex; // FIXUP later
+ e[i] = nameToEnum[i].enumValue;
+ }
+ return n2e;
+}
+
+
+void Builder::buildTopLevelProperties(const NameToEnumEntry* propName,
+ int32_t propNameCount,
+ const EnumToNameGroupEntry* propEnum,
+ int32_t propEnumCount) {
+ enumToName = buildNCEnumToNameGroup(propEnum,
+ propEnumCount,
+ enumToName_size);
+ nameToEnum = buildNameToEnum(propName,
+ propNameCount,
+ nameToEnum_size);
+}
+
+void Builder::buildValues(const EnumToValueEntry* e2v,
+ int32_t count) {
+ int32_t i;
+
+ U_ASSERT(!e2v->isContiguous(count));
+
+ valueMap_count = count;
+
+ enumToValue = buildNCEnumToValue(e2v, count,
+ enumToValue_size);
+
+ valueMap_size = align(count * sizeof(ValueMap));
+ valueMap = (ValueMap*) uprv_malloc(valueMap_size);
+ erase(valueMap, valueMap_size);
+
+ valueEnumToName = MALLOC(EnumToOffset*, count);
+ valueNCEnumToName = MALLOC(NonContiguousEnumToOffset*, count);
+ valueEnumToName_size = MALLOC(int32_t, count);
+ valueEnumToName_offset = MALLOC(Offset, count);
+ valueNameToEnum = MALLOC(NameToEnum*, count);
+ valueNameToEnum_size = MALLOC(int32_t, count);
+ valueNameToEnum_offset = MALLOC(Offset, count);
+
+ for (i=0; i<count; ++i) {
+ UBool isContiguous =
+ e2v[i].enumToName->isContiguous(e2v[i].enumToName_count);
+ valueEnumToName[i] = 0;
+ valueNCEnumToName[i] = 0;
+ if (isContiguous) {
+ valueEnumToName[i] = buildEnumToOffset(e2v[i].enumToName,
+ e2v[i].enumToName_count,
+ valueEnumToName_size[i]);
+ } else {
+ valueNCEnumToName[i] = buildNCEnumToNameGroup(e2v[i].enumToName,
+ e2v[i].enumToName_count,
+ valueEnumToName_size[i]);
+ }
+ valueNameToEnum[i] =
+ buildNameToEnum(e2v[i].nameToEnum,
+ e2v[i].nameToEnum_count,
+ valueNameToEnum_size[i]);
+ }
+}
+
+void Builder::buildStringPool(const AliasName* propertyNames,
+ int32_t propertyNameCount,
+ const int32_t* nameGroupIndices,
+ int32_t nameGroupIndicesCount) {
+ int32_t i;
+
+ nameGroupPool_count = nameGroupIndicesCount;
+ nameGroupPool_size = sizeof(Offset) * nameGroupPool_count;
+ nameGroupPool = MALLOC(Offset, nameGroupPool_count);
+
+ for (i=0; i<nameGroupPool_count; ++i) {
+ // Some indices are negative.
+ int32_t a = nameGroupIndices[i];
+ if (a < 0) a = -a;
+ U_ASSERT(IS_VALID_OFFSET(a));
+ nameGroupPool[i] = (Offset) nameGroupIndices[i];
+ }
+
+ stringPool_count = propertyNameCount;
+ stringPool_size = 0;
+ // first string must be "" -- we skip it
+ U_ASSERT(*propertyNames[0].str == 0);
+ for (i=1 /*sic*/; i<propertyNameCount; ++i) {
+ stringPool_size += (int32_t)(uprv_strlen(propertyNames[i].str) + 1);
+ }
+ stringPool = MALLOC(char, stringPool_size);
+ stringPool_offsetArray = MALLOC(Offset, stringPool_count);
+ Offset soFar = 0;
+ char* p = stringPool;
+ stringPool_offsetArray[0] = -1; // we don't use this entry
+ for (i=1 /*sic*/; i<propertyNameCount; ++i) {
+ const char* str = propertyNames[i].str;
+ int32_t len = (int32_t)uprv_strlen(str);
+ uprv_strcpy(p, str);
+ p += len;
+ *p++ = 0;
+ stringPool_offsetArray[i] = soFar;
+ soFar += (Offset)(len+1);
+ }
+ U_ASSERT(soFar == stringPool_size);
+ U_ASSERT(p == (stringPool + stringPool_size));
+}
+
+// Confirm that PropertyAliases is a POD (plain old data; see C++
+// std). The following union will _fail to compile_ if
+// PropertyAliases is _not_ a POD. (Note: We used to use the offsetof
+// macro to check this, but that's not quite right, so that test is
+// commented out -- see below.)
+typedef union {
+ int32_t i;
+ PropertyAliases p;
+} PropertyAliasesPODTest;
+
+void Builder::computeOffsets() {
+ int32_t i;
+ Offset off = sizeof(header);
+
+ if (debug>0) {
+ printf("header \t offset=%4d size=%5d\n", 0, off);
+ }
+
+ // PropertyAliases must have no v-table and must be
+ // padded (if necessary) to the next 32-bit boundary.
+ //U_ASSERT(offsetof(PropertyAliases, enumToName_offset) == 0); // see above
+ U_ASSERT(sizeof(header) % sizeof(int32_t) == 0);
+
+ #define COMPUTE_OFFSET(foo) COMPUTE_OFFSET2(foo,int32_t)
+
+ #define COMPUTE_OFFSET2(foo,type) \
+ if (debug>0)\
+ printf(#foo "\t offset=%4d size=%5d\n", off, (int)foo##_size);\
+ foo##_offset = off;\
+ U_ASSERT(IS_VALID_OFFSET(off + foo##_size));\
+ U_ASSERT(foo##_offset % sizeof(type) == 0);\
+ off = (Offset) (off + foo##_size);
+
+ COMPUTE_OFFSET(enumToName); // 0:
+ COMPUTE_OFFSET(nameToEnum); // 2:
+ COMPUTE_OFFSET(enumToValue); // 3:
+ COMPUTE_OFFSET(valueMap); // 4:
+
+ for (i=0; i<valueMap_count; ++i) {
+ if (debug>0) {
+ printf(" enumToName[%d]\t offset=%4d size=%5d\n",
+ (int)i, off, (int)valueEnumToName_size[i]);
+ }
+
+ valueEnumToName_offset[i] = off; // 5:
+ U_ASSERT(IS_VALID_OFFSET(off + valueEnumToName_size[i]));
+ off = (Offset) (off + valueEnumToName_size[i]);
+
+ if (debug>0) {
+ printf(" nameToEnum[%d]\t offset=%4d size=%5d\n",
+ (int)i, off, (int)valueNameToEnum_size[i]);
+ }
+
+ valueNameToEnum_offset[i] = off; // 6:
+ U_ASSERT(IS_VALID_OFFSET(off + valueNameToEnum_size[i]));
+ off = (Offset) (off + valueNameToEnum_size[i]);
+ }
+
+ // These last two chunks have weaker alignment needs
+ COMPUTE_OFFSET2(nameGroupPool,Offset); // 98:
+ COMPUTE_OFFSET2(stringPool,char); // 99:
+
+ total_size = off;
+ if (debug>0) printf("total size=%5d\n\n", (int)total_size);
+ U_ASSERT(total_size <= (MAX_OFFSET+1));
+}
+
+void Builder::fixupNameToEnum(NameToEnum* n) {
+ // Fix the string pool offsets in n
+ Offset* p = n->getNameArray();
+ for (int32_t i=0; i<n->count; ++i) {
+ p[i] = stringIndexToOffset(p[i]);
+ }
+}
+
+void Builder::fixupStringPoolOffsets() {
+ int32_t i;
+
+ // 2:
+ fixupNameToEnum(nameToEnum);
+
+ // 6:
+ for (i=0; i<valueMap_count; ++i) {
+ fixupNameToEnum(valueNameToEnum[i]);
+ }
+
+ // 98:
+ for (i=0; i<nameGroupPool_count; ++i) {
+ nameGroupPool[i] = stringIndexToOffset(nameGroupPool[i], TRUE);
+ }
+}
+
+void Builder::fixupEnumToNameGroup(EnumToOffset* e2ng) {
+ EnumValue i;
+ int32_t j;
+ Offset* p = e2ng->getOffsetArray();
+ for (i=e2ng->enumStart, j=0; i<e2ng->enumLimit; ++i, ++j) {
+ p[j] = nameGroupPool_offset + sizeof(Offset) * p[j];
+ }
+}
+
+void Builder::fixupNCEnumToNameGroup(NonContiguousEnumToOffset* e2ng) {
+ int32_t i;
+ /*EnumValue* e = e2ng->getEnumArray();*/
+ Offset* p = e2ng->getOffsetArray();
+ for (i=0; i<e2ng->count; ++i) {
+ p[i] = nameGroupPool_offset + sizeof(Offset) * p[i];
+ }
+}
+
+void Builder::fixupNameGroupPoolOffsets() {
+ int32_t i;
+
+ // 0:
+ fixupNCEnumToNameGroup(enumToName);
+
+ // 1: (deleted)
+
+ // 5:
+ for (i=0; i<valueMap_count; ++i) {
+ // 5a:
+ if (valueEnumToName[i] != 0) {
+ fixupEnumToNameGroup(valueEnumToName[i]);
+ }
+ // 5b:
+ if (valueNCEnumToName[i] != 0) {
+ fixupNCEnumToNameGroup(valueNCEnumToName[i]);
+ }
+ }
+}
+
+void Builder::fixupMiscellaneousOffsets() {
+ int32_t i;
+
+ // header:
+ erase(&header, sizeof(header));
+ header.enumToName_offset = enumToName_offset;
+ header.nameToEnum_offset = nameToEnum_offset;
+ header.enumToValue_offset = enumToValue_offset;
+ // header meta-info used by Java:
+ U_ASSERT(total_size > 0 && total_size < 0x7FFF);
+ header.total_size = (int16_t) total_size;
+ header.valueMap_offset = valueMap_offset;
+ header.valueMap_count = (int16_t) valueMap_count;
+ header.nameGroupPool_offset = nameGroupPool_offset;
+ header.nameGroupPool_count = (int16_t) nameGroupPool_count;
+ header.stringPool_offset = stringPool_offset;
+ header.stringPool_count = (int16_t) stringPool_count - 1; // don't include "" entry
+
+ U_ASSERT(valueMap_count <= 0x7FFF);
+ U_ASSERT(nameGroupPool_count <= 0x7FFF);
+ U_ASSERT(stringPool_count <= 0x7FFF);
+
+ // 3:
+ Offset* p = enumToValue->getOffsetArray();
+ /*EnumValue* e = enumToValue->getEnumArray();*/
+ U_ASSERT(valueMap_count == enumToValue->count);
+ for (i=0; i<valueMap_count; ++i) {
+ p[i] = (Offset)(valueMap_offset + sizeof(ValueMap) * i);
+ }
+
+ // 4:
+ for (i=0; i<valueMap_count; ++i) {
+ ValueMap& v = valueMap[i];
+ v.enumToName_offset = v.ncEnumToName_offset = 0;
+ if (valueEnumToName[i] != 0) {
+ v.enumToName_offset = valueEnumToName_offset[i];
+ }
+ if (valueNCEnumToName[i] != 0) {
+ v.ncEnumToName_offset = valueEnumToName_offset[i];
+ }
+ v.nameToEnum_offset = valueNameToEnum_offset[i];
+ }
+}
+
+void Builder::fixup() {
+ computeOffsets();
+ fixupStringPoolOffsets();
+ fixupNameGroupPoolOffsets();
+ fixupMiscellaneousOffsets();
+}
+
+int8_t* Builder::createData(int32_t& length) const {
+ length = total_size;
+ int8_t* result = MALLOC(int8_t, length);
+
+ int8_t* p = result;
+ int8_t* limit = result + length;
+
+ #define APPEND2(x, size) \
+ U_ASSERT((p+size)<=limit); \
+ uprv_memcpy(p, x, size); \
+ p += size
+
+ #define APPEND(x) APPEND2(x, x##_size)
+
+ APPEND2(&header, sizeof(header));
+ APPEND(enumToName);
+ APPEND(nameToEnum);
+ APPEND(enumToValue);
+ APPEND(valueMap);
+
+ for (int32_t i=0; i<valueMap_count; ++i) {
+ U_ASSERT((valueEnumToName[i] != 0 && valueNCEnumToName[i] == 0) ||
+ (valueEnumToName[i] == 0 && valueNCEnumToName[i] != 0));
+ if (valueEnumToName[i] != 0) {
+ APPEND2(valueEnumToName[i], valueEnumToName_size[i]);
+ }
+ if (valueNCEnumToName[i] != 0) {
+ APPEND2(valueNCEnumToName[i], valueEnumToName_size[i]);
+ }
+ APPEND2(valueNameToEnum[i], valueNameToEnum_size[i]);
+ }
+
+ APPEND(nameGroupPool);
+ APPEND(stringPool);
+
+ if (p != limit) {
+ fprintf(stderr, "p != limit; p = %p, limit = %p", p, limit);
+ exit(1);
+ }
+ return result;
+}
+
+// END Builder
+//----------------------------------------------------------------------
+
+/* UDataInfo cf. udata.h */
+static UDataInfo dataInfo = {
+ sizeof(UDataInfo),
+ 0,
+
+ U_IS_BIG_ENDIAN,
+ U_CHARSET_FAMILY,
+ sizeof(UChar),
+ 0,
+
+ {PNAME_SIG_0, PNAME_SIG_1, PNAME_SIG_2, PNAME_SIG_3},
+ {PNAME_FORMAT_VERSION, 0, 0, 0}, /* formatVersion */
+ {VERSION_0, VERSION_1, VERSION_2, VERSION_3} /* Unicode version */
+};
+
+class genpname {
+
+ // command-line options
+ UBool useCopyright;
+ UBool verbose;
+ int32_t debug;
+
+public:
+ int MMain(int argc, char *argv[]);
+
+private:
+ NameToEnumEntry* createNameIndex(const AliasList& list,
+ int32_t& nameIndexCount);
+
+ EnumToNameGroupEntry* createEnumIndex(const AliasList& list);
+
+ int32_t writeDataFile(const char *destdir, const Builder&);
+};
+
+int main(int argc, char *argv[]) {
+ UErrorCode status = U_ZERO_ERROR;
+ u_init(&status);
+ if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) {
+ // Note: u_init() will try to open ICU property data.
+ // failures here are expected when building ICU from scratch.
+ // ignore them.
+ fprintf(stderr, "genpname: can not initialize ICU. Status = %s\n",
+ u_errorName(status));
+ exit(1);
+ }
+
+ genpname app;
+ U_MAIN_INIT_ARGS(argc, argv);
+ int retVal = app.MMain(argc, argv);
+ u_cleanup();
+ return retVal;
+}
+
+static UOption options[]={
+ UOPTION_HELP_H,
+ UOPTION_HELP_QUESTION_MARK,
+ UOPTION_COPYRIGHT,
+ UOPTION_DESTDIR,
+ UOPTION_VERBOSE,
+ UOPTION_DEF("debug", 'D', UOPT_REQUIRES_ARG),
+};
+
+NameToEnumEntry* genpname::createNameIndex(const AliasList& list,
+ int32_t& nameIndexCount) {
+
+ // Build name => enum map
+
+ // This is an n->1 map. There are typically multiple names
+ // mapping to one enum. The name index is sorted in order of the name,
+ // as defined by the uprv_compareAliasNames() function.
+
+ int32_t i, j;
+ int32_t count = list.count();
+
+ // compute upper limit on number of names in the index
+ int32_t nameIndexCapacity = count * MAX_NAMES_PER_GROUP;
+ NameToEnumEntry* nameIndex = MALLOC(NameToEnumEntry, nameIndexCapacity);
+
+ nameIndexCount = 0;
+ int32_t names[MAX_NAMES_PER_GROUP];
+ for (i=0; i<count; ++i) {
+ const Alias& p = list[i];
+ int32_t n = p.getUniqueNames(names);
+ for (j=0; j<n; ++j) {
+ U_ASSERT(nameIndexCount < nameIndexCapacity);
+ nameIndex[nameIndexCount++] =
+ NameToEnumEntry(names[j], p.enumValue);
+ }
+ }
+
+ /*
+ * use a stable sort to ensure consistent results between
+ * genpname.cpp and the propname.cpp swapping code
+ */
+ UErrorCode errorCode = U_ZERO_ERROR;
+ uprv_sortArray(nameIndex, nameIndexCount, sizeof(nameIndex[0]),
+ compareNameToEnumEntry, NULL, TRUE, &errorCode);
+ if (debug>1) {
+ printf("Alias names: %d\n", (int)nameIndexCount);
+ for (i=0; i<nameIndexCount; ++i) {
+ printf("%s => %d\n",
+ STRING_TABLE[nameIndex[i].nameIndex].str,
+ (int)nameIndex[i].enumValue);
+ }
+ printf("\n");
+ }
+ // make sure there are no duplicates. for a sorted list we need
+ // only compare adjacent items. Alias.getUniqueNames() has
+ // already eliminated duplicate names for a single property, which
+ // does occur, so we're checking for duplicate names between two
+ // properties, which should never occur.
+ UBool ok = TRUE;
+ for (i=1; i<nameIndexCount; ++i) {
+ if (STRING_TABLE[nameIndex[i-1].nameIndex] ==
+ STRING_TABLE[nameIndex[i].nameIndex]) {
+ printf("Error: Duplicate names in property list: \"%s\", \"%s\"\n",
+ STRING_TABLE[nameIndex[i-1].nameIndex].str,
+ STRING_TABLE[nameIndex[i].nameIndex].str);
+ ok = FALSE;
+ }
+ }
+ if (!ok) {
+ die("Two or more duplicate names in property list");
+ }
+
+ return nameIndex;
+}
+
+EnumToNameGroupEntry* genpname::createEnumIndex(const AliasList& list) {
+
+ // Build the enum => name map
+
+ // This is a 1->n map. Each enum maps to 1 or more names. To
+ // accomplish this the index entry points to an element of the
+ // NAME_GROUP array. This is the short name (which may be empty).
+ // From there, subsequent elements of NAME_GROUP are alternate
+ // names for this enum, up to and including the first one that is
+ // negative (negate for actual index).
+
+ int32_t i, j, k;
+ int32_t count = list.count();
+
+ EnumToNameGroupEntry* enumIndex = MALLOC(EnumToNameGroupEntry, count);
+ for (i=0; i<count; ++i) {
+ const Alias& p = list[i];
+ enumIndex[i] = EnumToNameGroupEntry(p.enumValue, p.nameGroupIndex);
+ }
+
+ UErrorCode errorCode = U_ZERO_ERROR;
+ uprv_sortArray(enumIndex, count, sizeof(enumIndex[0]),
+ compareEnumToNameGroupEntry, NULL, FALSE, &errorCode);
+ if (debug>1) {
+ printf("Property enums: %d\n", (int)count);
+ for (i=0; i<count; ++i) {
+ printf("%d => %d: ",
+ (int)enumIndex[i].enumValue,
+ (int)enumIndex[i].nameGroupIndex);
+ UBool done = FALSE;
+ for (j=enumIndex[i].nameGroupIndex; !done; ++j) {
+ k = NAME_GROUP[j];
+ if (k < 0) {
+ k = -k;
+ done = TRUE;
+ }
+ printf("\"%s\"", STRING_TABLE[k].str);
+ if (!done) printf(", ");
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+ return enumIndex;
+}
+
+int genpname::MMain(int argc, char* argv[])
+{
+ int32_t i, j;
+ UErrorCode status = U_ZERO_ERROR;
+
+ u_init(&status);
+ if (U_FAILURE(status) && status != U_FILE_ACCESS_ERROR) {
+ fprintf(stderr, "Error: u_init returned %s\n", u_errorName(status));
+ status = U_ZERO_ERROR;
+ }
+
+
+ /* preset then read command line options */
+ options[3].value=u_getDataDirectory();
+ argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
+
+ /* error handling, printing usage message */
+ if (argc<0) {
+ fprintf(stderr,
+ "error in command line argument \"%s\"\n",
+ argv[-argc]);
+ }
+
+ debug = options[5].doesOccur ? (*options[5].value - '0') : 0;
+
+ if (argc!=1 || options[0].doesOccur || options[1].doesOccur ||
+ debug < 0 || debug > 9) {
+ fprintf(stderr,
+ "usage: %s [-options]\n"
+ "\tcreate " PNAME_DATA_NAME "." PNAME_DATA_TYPE "\n"
+ "options:\n"
+ "\t-h or -? or --help this usage text\n"
+ "\t-v or --verbose turn on verbose output\n"
+ "\t-c or --copyright include a copyright notice\n"
+ "\t-d or --destdir destination directory, followed by the path\n"
+ "\t-D or --debug 0..9 emit debugging messages (if > 0)\n",
+ argv[0]);
+ return argc<0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR;
+ }
+
+ /* get the options values */
+ useCopyright=options[2].doesOccur;
+ verbose = options[4].doesOccur;
+
+ // ------------------------------------------------------------
+ // Do not sort the string table, instead keep it in data.h order.
+ // This simplifies data swapping and testing thereof because the string
+ // table itself need not be sorted during swapping.
+ // The NameToEnum sorter sorts each such map's string offsets instead.
+
+ if (debug>1) {
+ printf("String pool: %d\n", (int)STRING_COUNT);
+ for (i=0; i<STRING_COUNT; ++i) {
+ if (i != 0) {
+ printf(", ");
+ }
+ printf("%s (%d)", STRING_TABLE[i].str, (int)STRING_TABLE[i].index);
+ }
+ printf("\n\n");
+ }
+
+ // ------------------------------------------------------------
+ // Create top-level property indices
+
+ PropertyArrayList props(PROPERTY, PROPERTY_COUNT);
+ int32_t propNameCount;
+ NameToEnumEntry* propName = createNameIndex(props, propNameCount);
+ EnumToNameGroupEntry* propEnum = createEnumIndex(props);
+
+ // ------------------------------------------------------------
+ // Create indices for the value list for each enumerated property
+
+ // This will have more entries than we need...
+ EnumToValueEntry* enumToValue = MALLOC(EnumToValueEntry, PROPERTY_COUNT);
+ int32_t enumToValue_count = 0;
+ for (i=0, j=0; i<PROPERTY_COUNT; ++i) {
+ if (PROPERTY[i].valueCount == 0) continue;
+ AliasArrayList values(PROPERTY[i].valueList,
+ PROPERTY[i].valueCount);
+ enumToValue[j].enumValue = PROPERTY[i].enumValue;
+ enumToValue[j].enumToName = createEnumIndex(values);
+ enumToValue[j].enumToName_count = PROPERTY[i].valueCount;
+ enumToValue[j].nameToEnum = createNameIndex(values,
+ enumToValue[j].nameToEnum_count);
+ ++j;
+ }
+ enumToValue_count = j;
+
+ uprv_sortArray(enumToValue, enumToValue_count, sizeof(enumToValue[0]),
+ compareEnumToValueEntry, NULL, FALSE, &status);
+
+ // ------------------------------------------------------------
+ // Build PropertyAliases layout in memory
+
+ Builder builder(debug);
+
+ builder.buildTopLevelProperties(propName,
+ propNameCount,
+ propEnum,
+ PROPERTY_COUNT);
+
+ builder.buildValues(enumToValue,
+ enumToValue_count);
+
+ builder.buildStringPool(STRING_TABLE,
+ STRING_COUNT,
+ NAME_GROUP,
+ NAME_GROUP_COUNT);
+
+ builder.fixup();
+
+ ////////////////////////////////////////////////////////////
+ // Write the output file
+ ////////////////////////////////////////////////////////////
+ int32_t wlen = writeDataFile(options[3].value, builder);
+ if (verbose) {
+ fprintf(stdout, "Output file: %s.%s, %ld bytes\n",
+ U_ICUDATA_NAME "_" PNAME_DATA_NAME, PNAME_DATA_TYPE, (long)wlen);
+ }
+
+ return 0; // success
+}
+
+int32_t genpname::writeDataFile(const char *destdir, const Builder& builder) {
+ int32_t length;
+ int8_t* data = builder.createData(length);
+
+ UNewDataMemory *pdata;
+ UErrorCode status = U_ZERO_ERROR;
+
+ pdata = udata_create(destdir, PNAME_DATA_TYPE, PNAME_DATA_NAME, &dataInfo,
+ useCopyright ? U_COPYRIGHT_STRING : 0, &status);
+ if (U_FAILURE(status)) {
+ die("Unable to create data memory");
+ }
+
+ udata_writeBlock(pdata, data, length);
+
+ int32_t dataLength = (int32_t) udata_finish(pdata, &status);
+ if (U_FAILURE(status)) {
+ die("Error writing output file");
+ }
+ if (dataLength != length) {
+ die("Written file doesn't match expected size");
+ }
+
+ return dataLength;
+}
+
+//eof