1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 **********************************************************************
5 *   Copyright (C) 2001-2011, International Business Machines
6 *   Corporation and others.  All Rights Reserved.
7 **********************************************************************
8 *   Date        Name        Description
9 *   06/06/01    aliu        Creation.
10 **********************************************************************
11 */
12 
13 #include "unicode/utypes.h"
14 
15 #if !UCONFIG_NO_TRANSLITERATION
16 
17 #include "unicode/unifilt.h"
18 #include "unicode/uchar.h"
19 #include "unicode/utf16.h"
20 #include "uni2name.h"
21 #include "cstring.h"
22 #include "cmemory.h"
23 #include "uprops.h"
24 
25 U_NAMESPACE_BEGIN
26 
27 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnicodeNameTransliterator)
28 
29 static const UChar OPEN_DELIM[] = {92,78,123,0}; // "\N{"
30 static const UChar CLOSE_DELIM  = 125; // "}"
31 #define OPEN_DELIM_LEN 3
32 
33 /**
34  * Constructs a transliterator.
35  */
36 UnicodeNameTransliterator::UnicodeNameTransliterator(UnicodeFilter* adoptedFilter) :
37     Transliterator(UNICODE_STRING("Any-Name", 8), adoptedFilter) {
38 }
39 
40 /**
41  * Destructor.
42  */
43 UnicodeNameTransliterator::~UnicodeNameTransliterator() {}
44 
45 /**
46  * Copy constructor.
47  */
48 UnicodeNameTransliterator::UnicodeNameTransliterator(const UnicodeNameTransliterator& o) :
49     Transliterator(o) {}
50 
51 /**
52  * Assignment operator.
53  */
54 /*UnicodeNameTransliterator& UnicodeNameTransliterator::operator=(
55                              const UnicodeNameTransliterator& o) {
56     Transliterator::operator=(o);
57     return *this;
58 }*/
59 
60 /**
61  * Transliterator API.
62  */
63 Transliterator* UnicodeNameTransliterator::clone(void) const {
64     return new UnicodeNameTransliterator(*this);
65 }
66 
67 /**
68  * Implements {@link Transliterator#handleTransliterate}.
69  * Ignore isIncremental since we don't need the context, and
70  * we work on codepoints.
71  */
72 void UnicodeNameTransliterator::handleTransliterate(Replaceable& text, UTransPosition& offsets,
73                                                     UBool /*isIncremental*/) const {
74     // The failure mode, here and below, is to behave like Any-Null,
75     // if either there is no name data (max len == 0) or there is no
76     // memory (malloc() => NULL).
77 
78     int32_t maxLen = uprv_getMaxCharNameLength();
79     if (maxLen == 0) {
80         offsets.start = offsets.limit;
81         return;
82     }
83 
84     // Accomodate the longest possible name plus padding
85     char* buf = (char*) uprv_malloc(maxLen);
86     if (buf == NULL) {
87         offsets.start = offsets.limit;
88         return;
89     }
90 
91     int32_t cursor = offsets.start;
92     int32_t limit = offsets.limit;
93 
94     UnicodeString str(FALSE, OPEN_DELIM, OPEN_DELIM_LEN);
95     UErrorCode status;
96     int32_t len;
97 
98     while (cursor < limit) {
99         UChar32 c = text.char32At(cursor);
100         int32_t clen = U16_LENGTH(c);
101         status = U_ZERO_ERROR;
102         if ((len = u_charName(c, U_EXTENDED_CHAR_NAME, buf, maxLen, &status)) >0 && !U_FAILURE(status)) {
103             str.truncate(OPEN_DELIM_LEN);
104             str.append(UnicodeString(buf, len, US_INV)).append(CLOSE_DELIM);
105             text.handleReplaceBetween(cursor, cursor+clen, str);
106             len += OPEN_DELIM_LEN + 1; // adjust for delimiters
107             cursor += len; // advance cursor and adjust for new text
108             limit += len-clen; // change in length
109         } else {
110             cursor += clen;
111         }
112     }
113 
114     offsets.contextLimit += limit - offsets.limit;
115     offsets.limit = limit;
116     offsets.start = cursor;
117 
118     uprv_free(buf);
119 }
120 
121 U_NAMESPACE_END
122 
123 #endif /* #if !UCONFIG_NO_TRANSLITERATION */
124