+void
+Normalizer2DataBuilder::writeCSourceFile(const char *filename) {
+ LocalUCPTriePointer norm16Trie = processData();
+
+ IcuToolErrorCode errorCode("gennorm2/writeCSourceFile()");
+ const char *basename=findBasename(filename);
+ CharString path(filename, (int32_t)(basename-filename), errorCode);
+ CharString dataName(basename, errorCode);
+ const char *extension=strrchr(basename, '.');
+ if(extension!=NULL) {
+ dataName.truncate((int32_t)(extension-basename));
+ }
+ const char *name=dataName.data();
+ errorCode.assertSuccess();
+
+ FILE *f=usrc_create(path.data(), basename, 2016, "icu/source/tools/gennorm2/n2builder.cpp");
+ if(f==NULL) {
+ fprintf(stderr, "gennorm2/writeCSourceFile() error: unable to create the output file %s\n",
+ filename);
+ exit(U_FILE_ACCESS_ERROR);
+ }
+ fputs("#ifdef INCLUDED_FROM_NORMALIZER2_CPP\n\n", f);
+
+ char line[100];
+ sprintf(line, "static const UVersionInfo %s_formatVersion={", name);
+ usrc_writeArray(f, line, dataInfo.formatVersion, 8, 4, "};\n");
+ sprintf(line, "static const UVersionInfo %s_dataVersion={", name);
+ usrc_writeArray(f, line, dataInfo.dataVersion, 8, 4, "};\n\n");
+ sprintf(line, "static const int32_t %s_indexes[Normalizer2Impl::IX_COUNT]={\n", name);
+ usrc_writeArray(f, line, indexes, 32, Normalizer2Impl::IX_COUNT, "\n};\n\n");
+
+ usrc_writeUCPTrie(f, name, norm16Trie.getAlias());
+
+ sprintf(line, "static const uint16_t %s_extraData[%%ld]={\n", name);
+ usrc_writeArray(f, line, extraData.getBuffer(), 16, extraData.length(), "\n};\n\n");
+ sprintf(line, "static const uint8_t %s_smallFCD[%%ld]={\n", name);
+ usrc_writeArray(f, line, smallFCD, 8, sizeof(smallFCD), "\n};\n\n");
+
+ fputs("#endif // INCLUDED_FROM_NORMALIZER2_CPP\n", f);
+ fclose(f);
+}
+
+namespace {
+
+bool equalStrings(const UnicodeString *s1, const UnicodeString *s2) {
+ if(s1 == nullptr) {
+ return s2 == nullptr;
+ } else if(s2 == nullptr) {
+ return false;
+ } else {
+ return *s1 == *s2;
+ }
+}
+
+const char *typeChars = "?-=>";
+
+void writeMapping(FILE *f, const UnicodeString *m) {
+ if(m != nullptr && !m->isEmpty()) {
+ int32_t i = 0;
+ UChar32 c = m->char32At(i);
+ fprintf(f, "%04lX", (long)c);
+ while((i += U16_LENGTH(c)) < m->length()) {
+ c = m->char32At(i);
+ fprintf(f, " %04lX", (long)c);
+ }
+ }
+ fputs("\n", f);
+}
+
+} // namespace
+
+void
+Normalizer2DataBuilder::writeDataFile(const char *filename, bool writeRemoved) const {
+ // Do not processData() before writing the input-syntax data file.
+ FILE *f = fopen(filename, "w");
+ if(f == nullptr) {
+ fprintf(stderr, "gennorm2/writeDataFile() error: unable to create the output file %s\n",
+ filename);
+ exit(U_FILE_ACCESS_ERROR);
+ return;
+ }
+
+ if(unicodeVersion[0] != 0 || unicodeVersion[1] != 0 ||
+ unicodeVersion[2] != 0 || unicodeVersion[3] != 0) {
+ char uv[U_MAX_VERSION_STRING_LENGTH];
+ u_versionToString(unicodeVersion, uv);
+ fprintf(f, "* Unicode %s\n\n", uv);
+ }
+
+ UnicodeSetIterator ccIter(norms.ccSet);
+ UChar32 start = U_SENTINEL;
+ UChar32 end = U_SENTINEL;
+ uint8_t prevCC = 0;
+ bool done = false;
+ bool didWrite = false;
+ do {
+ UChar32 c;
+ uint8_t cc;
+ if(ccIter.next() && !ccIter.isString()) {
+ c = ccIter.getCodepoint();
+ cc = norms.getCC(c);
+ } else {
+ c = 0x110000;
+ cc = 0;
+ done = true;
+ }
+ if(cc == prevCC && c == (end + 1)) {
+ end = c;
+ } else {
+ if(prevCC != 0) {
+ if(start == end) {
+ fprintf(f, "%04lX:%d\n", (long)start, (int)prevCC);
+ } else {
+ fprintf(f, "%04lX..%04lX:%d\n", (long)start, (long)end, (int)prevCC);
+ }
+ didWrite = true;
+ }
+ start = end = c;
+ prevCC = cc;
+ }
+ } while(!done);
+ if(didWrite) {
+ fputs("\n", f);
+ }
+
+ UnicodeSetIterator mIter(norms.mappingSet);
+ start = U_SENTINEL;
+ end = U_SENTINEL;
+ const UnicodeString *prevMapping = nullptr;
+ Norm::MappingType prevType = Norm::NONE;
+ done = false;
+ do {
+ UChar32 c;
+ const Norm *norm;
+ if(mIter.next() && !mIter.isString()) {
+ c = mIter.getCodepoint();
+ norm = norms.getNorm(c);
+ } else {
+ c = 0x110000;
+ norm = nullptr;
+ done = true;
+ }
+ const UnicodeString *mapping;
+ Norm::MappingType type;
+ if(norm == nullptr) {
+ mapping = nullptr;
+ type = Norm::NONE;
+ } else {
+ type = norm->mappingType;
+ if(type == Norm::NONE) {
+ mapping = nullptr;
+ } else {
+ mapping = norm->mapping;
+ }
+ }
+ if(type == prevType && equalStrings(mapping, prevMapping) && c == (end + 1)) {
+ end = c;
+ } else {
+ if(writeRemoved ? prevType != Norm::NONE : prevType > Norm::REMOVED) {
+ if(start == end) {
+ fprintf(f, "%04lX%c", (long)start, typeChars[prevType]);
+ } else {
+ fprintf(f, "%04lX..%04lX%c", (long)start, (long)end, typeChars[prevType]);
+ }
+ writeMapping(f, prevMapping);
+ }
+ start = end = c;
+ prevMapping = mapping;
+ prevType = type;
+ }
+ } while(!done);
+
+ fclose(f);
+}
+
+void
+Normalizer2DataBuilder::computeDiff(const Normalizer2DataBuilder &b1,
+ const Normalizer2DataBuilder &b2,
+ Normalizer2DataBuilder &diff) {
+ // Compute diff = b1 - b2
+ // so that we should be able to get b1 = b2 + diff.
+ if(0 != memcmp(b1.unicodeVersion, b2.unicodeVersion, U_MAX_VERSION_LENGTH)) {
+ memcpy(diff.unicodeVersion, b1.unicodeVersion, U_MAX_VERSION_LENGTH);
+ }
+
+ UnicodeSet ccSet(b1.norms.ccSet);
+ ccSet.addAll(b2.norms.ccSet);
+ UnicodeSetIterator ccIter(ccSet);
+ while(ccIter.next() && !ccIter.isString()) {
+ UChar32 c = ccIter.getCodepoint();
+ uint8_t cc1 = b1.norms.getCC(c);
+ uint8_t cc2 = b2.norms.getCC(c);
+ if(cc1 != cc2) {
+ diff.setCC(c, cc1);
+ }
+ }
+
+ UnicodeSet mSet(b1.norms.mappingSet);
+ mSet.addAll(b2.norms.mappingSet);
+ UnicodeSetIterator mIter(mSet);
+ while(mIter.next() && !mIter.isString()) {
+ UChar32 c = mIter.getCodepoint();
+ const Norm *norm1 = b1.norms.getNorm(c);
+ const Norm *norm2 = b2.norms.getNorm(c);
+ const UnicodeString *mapping1;
+ Norm::MappingType type1;
+ if(norm1 == nullptr || !norm1->hasMapping()) {
+ mapping1 = nullptr;
+ type1 = Norm::NONE;
+ } else {
+ mapping1 = norm1->mapping;
+ type1 = norm1->mappingType;
+ }
+ const UnicodeString *mapping2;
+ Norm::MappingType type2;
+ if(norm2 == nullptr || !norm2->hasMapping()) {
+ mapping2 = nullptr;
+ type2 = Norm::NONE;
+ } else {
+ mapping2 = norm2->mapping;
+ type2 = norm2->mappingType;
+ }
+ if(type1 == type2 && equalStrings(mapping1, mapping2)) {
+ // Nothing to do.
+ } else if(type1 == Norm::NONE) {
+ diff.removeMapping(c);
+ } else if(type1 == Norm::ROUND_TRIP) {
+ diff.setRoundTripMapping(c, *mapping1);
+ } else if(type1 == Norm::ONE_WAY) {
+ diff.setOneWayMapping(c, *mapping1);
+ }
+ }
+}
+