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 /////////////////////////////////////////////////////////////////////////////
30 IMPLEMENT_DEFAULT_EXTENSION_VERSION(idn
, NO_EXTENSION_VERSION_YET
);
33 INTL_IDNA_VARIANT_2003
= 0,
34 INTL_IDNA_VARIANT_UTS46
37 static Variant
doIdnTranslate2003(const String
& domain
, int64_t options
,
39 UErrorCode error
= U_ZERO_ERROR
;
40 icu::UnicodeString
uDomain(u16(domain
, error
));
41 if (U_FAILURE(error
)) {
42 s_intl_error
->setError(error
);
45 icu::UnicodeString ret
;
46 UChar
*retBuffer
= ret
.getBuffer(64);
49 UParseError parseError
;
52 len
= uidna_IDNToUnicode(uDomain
.getBuffer(), uDomain
.length(),
53 retBuffer
, ret
.getCapacity(),
54 options
, &parseError
, &error
);
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
;
67 retBuffer
= ret
.getBuffer(len
);
69 ret
.releaseBuffer(len
);
71 if (U_FAILURE(error
)) {
72 s_intl_error
->setError(error
);
77 String
out(u8(ret
, error
));
78 if (U_FAILURE(error
)) {
79 s_intl_error
->setError(error
, "Error converting result from Unicode");
85 #ifdef UIDNA_INFO_INITIALIZER // Indicates ICU >= 4.6
88 s_isTransitionalDifferent("isTransitionalDifferent"),
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
101 auto capacity
= result
.get()->capacity();
103 len
= uidna_nameToUnicodeUTF8(idna
, domain
.c_str(), domain
.size(),
104 result
.bufferSlice().ptr
, capacity
,
107 len
= uidna_nameToASCII_UTF8(idna
, domain
.c_str(), domain
.size(),
108 result
.bufferSlice().ptr
, capacity
,
111 if (len
> capacity
) {
112 s_intl_error
->setError(U_INTERNAL_PROGRAM_ERROR
);
115 if (U_FAILURE(error
)) {
116 s_intl_error
->setError(error
);
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();
132 s_intl_error
->setError(U_UNSUPPORTED_ERROR
);
137 inline Variant
doIdnTranslate(const String
& domain
, int64_t options
,
138 IdnVariant variant
, VRefParam info
,
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
);
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 /////////////////////////////////////////////////////////////////////////////
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