remove operator-> from String
[hiphop-php.git] / hphp / runtime / ext / icu / ext_icu_misc.cpp
blob08ebb71f57fbf394307f8338cce1c9ea18ee429c
1 #include "hphp/runtime/ext/icu/icu.h"
3 #include <unicode/uidna.h>
4 #include <unicode/parseerr.h>
6 namespace HPHP { namespace Intl {
8 /////////////////////////////////////////////////////////////////////////////
9 // Global error code/message
11 static int64_t HHVM_FUNCTION(intl_get_error_code) {
12 return s_intl_error->getErrorCode();
15 static String HHVM_FUNCTION(intl_get_error_message) {
16 return s_intl_error->getErrorMessage();
19 static String HHVM_FUNCTION(intl_error_name, int64_t errorCode) {
20 return String(u_errorName((UErrorCode)errorCode), CopyString);
23 static bool HHVM_FUNCTION(intl_is_failure, int64_t errorCode) {
24 return U_FAILURE((UErrorCode)errorCode);
27 /////////////////////////////////////////////////////////////////////////////
28 // IDNA functions
30 IMPLEMENT_DEFAULT_EXTENSION_VERSION(idn, NO_EXTENSION_VERSION_YET);
32 enum IdnVariant {
33 INTL_IDNA_VARIANT_2003 = 0,
34 INTL_IDNA_VARIANT_UTS46
37 static Variant doIdnTranslate2003(const String& domain, int64_t options,
38 bool toUtf8) {
39 UErrorCode error = U_ZERO_ERROR;
40 icu::UnicodeString uDomain(u16(domain, error));
41 if (U_FAILURE(error)) {
42 s_intl_error->setError(error);
43 return false;
45 icu::UnicodeString ret;
46 UChar *retBuffer = ret.getBuffer(64);
47 int32_t len = 0;
48 for(;;) {
49 UParseError parseError;
50 error = U_ZERO_ERROR;
51 if (toUtf8) {
52 len = uidna_IDNToUnicode(uDomain.getBuffer(), uDomain.length(),
53 retBuffer, ret.getCapacity(),
54 options, &parseError, &error);
55 } else {
56 len = uidna_IDNToASCII(uDomain.getBuffer(), uDomain.length(),
57 retBuffer, ret.getCapacity(),
58 options, &parseError, &error);
60 if (error != U_BUFFER_OVERFLOW_ERROR) break;
61 if (len < ret.getCapacity()) {
62 // Bufferoverflow which didn't overflow the buffer???
63 error = U_INTERNAL_PROGRAM_ERROR;
64 break;
66 ret.releaseBuffer(0);
67 retBuffer = ret.getBuffer(len);
69 ret.releaseBuffer(len);
71 if (U_FAILURE(error)) {
72 s_intl_error->setError(error);
73 return false;
76 error = U_ZERO_ERROR;
77 String out(u8(ret, error));
78 if (U_FAILURE(error)) {
79 s_intl_error->setError(error, "Error converting result from Unicode");
80 return false;
82 return out;
85 #ifdef UIDNA_INFO_INITIALIZER // Indicates ICU >= 4.6
86 const StaticString
87 s_result("result"),
88 s_isTransitionalDifferent("isTransitionalDifferent"),
89 s_errors("errors");
90 #endif
92 static Variant doIdnTranslateUTS46(const String& domain, int64_t options,
93 VRefParam retInfo, bool toUtf8) {
94 #ifdef UIDNA_INFO_INITIALIZER
95 UErrorCode error = U_ZERO_ERROR;
96 UIDNAInfo info = UIDNA_INFO_INITIALIZER;
97 auto idna = uidna_openUTS46(options, &error);
98 SCOPE_EXIT{ uidna_close(idna); };
99 String result(255, ReserveString); // 255 == max length possible
100 int32_t len;
101 auto capacity = result.get()->capacity();
102 if (toUtf8) {
103 len = uidna_nameToUnicodeUTF8(idna, domain.c_str(), domain.size(),
104 result.bufferSlice().ptr, capacity,
105 &info, &error);
106 } else {
107 len = uidna_nameToASCII_UTF8(idna, domain.c_str(), domain.size(),
108 result.bufferSlice().ptr, capacity,
109 &info, &error);
111 if (len > capacity) {
112 s_intl_error->setError(U_INTERNAL_PROGRAM_ERROR);
113 return false;
115 if (U_FAILURE(error)) {
116 s_intl_error->setError(error);
117 return false;
119 if (info.errors) {
120 return false;
122 result.setSize(len);
124 ArrayInit arr(3);
125 arr.set(s_result, result);
126 arr.set(s_isTransitionalDifferent, info.isTransitionalDifferent);
127 arr.set(s_errors, (long)info.errors);
128 retInfo = arr.create();
129 return result;
131 #else
132 s_intl_error->setError(U_UNSUPPORTED_ERROR);
133 return false;
134 #endif
137 inline Variant doIdnTranslate(const String& domain, int64_t options,
138 IdnVariant variant, VRefParam info,
139 bool toUtf8) {
140 switch (variant) {
141 case INTL_IDNA_VARIANT_2003:
142 return doIdnTranslate2003(domain, options, toUtf8);
143 case INTL_IDNA_VARIANT_UTS46:
144 return doIdnTranslateUTS46(domain, options, info, toUtf8);
146 return false;
149 static Variant HHVM_FUNCTION(idn_to_ascii, const String& domain,
150 int64_t options /*= 0 */,
151 int64_t variant /*= *_2003 */,
152 VRefParam info /*= null */) {
153 return doIdnTranslate(domain, options, (IdnVariant)variant, info, false);
156 static Variant HHVM_FUNCTION(idn_to_utf8, const String& domain,
157 int64_t options /*= 0 */,
158 int64_t variant /*= *_2003 */,
159 VRefParam info /*= null */) {
160 return doIdnTranslate(domain, options, (IdnVariant)variant, info, true);
163 /////////////////////////////////////////////////////////////////////////////
165 const StaticString
166 s_INTL_IDNA_VARIANT_2003("INTL_IDNA_VARIANT_2003"),
167 s_INTL_IDNA_VARIANT_UTS46("INTL_IDNA_VARIANT_UTS46");
169 void IntlExtension::initMisc() {
170 HHVM_FE(intl_get_error_code);
171 HHVM_FE(intl_get_error_message);
172 HHVM_FE(intl_error_name);
173 HHVM_FE(intl_is_failure);
175 HHVM_FE(idn_to_ascii);
176 HHVM_FE(idn_to_utf8);
178 Native::registerConstant<KindOfInt64>(s_INTL_IDNA_VARIANT_2003.get(),
179 INTL_IDNA_VARIANT_2003);
180 Native::registerConstant<KindOfInt64>(s_INTL_IDNA_VARIANT_UTS46.get(),
181 INTL_IDNA_VARIANT_UTS46);
183 loadSystemlib("icu_misc");
186 /////////////////////////////////////////////////////////////////////////////
187 }} // namespace HPHP::Intl