You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
6.3 KiB

  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Stanislav Malyshev <stas@zend.com> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19. // Fix build on Windows / old versions of ICU
  20. #include <stdio.h>
  21. #include <math.h>
  22. #include <unicode/msgfmt.h>
  23. #include <unicode/chariter.h>
  24. extern "C" {
  25. #include "php_intl.h"
  26. #include "msgformat_class.h"
  27. #include "msgformat_format.h"
  28. #include "msgformat_helpers.h"
  29. #include "intl_convert.h"
  30. }
  31. U_NAMESPACE_BEGIN
  32. /**
  33. * This class isolates our access to private internal methods of
  34. * MessageFormat. It is never instantiated; it exists only for C++
  35. * access management.
  36. */
  37. class MessageFormatAdapter {
  38. public:
  39. static const Formattable::Type* getArgTypeList(const MessageFormat& m,
  40. int32_t& count);
  41. };
  42. const Formattable::Type*
  43. MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
  44. int32_t& count) {
  45. return m.getArgTypeList(count);
  46. }
  47. U_NAMESPACE_END
  48. U_CFUNC int32_t umsg_format_arg_count(UMessageFormat *fmt)
  49. {
  50. int32_t fmt_count = 0;
  51. MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count);
  52. return fmt_count;
  53. }
  54. U_CFUNC void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args, UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC)
  55. {
  56. int fmt_count = 0;
  57. const Formattable::Type* argTypes =
  58. MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count);
  59. Formattable* fargs = new Formattable[fmt_count ? fmt_count : 1];
  60. for(int32_t i = 0; i < fmt_count; ++i) {
  61. UChar *stringVal = NULL;
  62. int stringLen = 0;
  63. int64_t tInt64 = 0;
  64. switch(argTypes[i]) {
  65. case Formattable::kDate:
  66. convert_to_long_ex(&args[i]);
  67. fargs[i].setDate(U_MILLIS_PER_SECOND * (double)Z_LVAL_P(args[i]));
  68. break;
  69. case Formattable::kDouble:
  70. convert_to_double_ex(&args[i]);
  71. fargs[i].setDouble(Z_DVAL_P(args[i]));
  72. break;
  73. case Formattable::kLong:
  74. convert_to_long_ex(&args[i]);
  75. fargs[i].setLong(Z_LVAL_P(args[i]));
  76. break;
  77. case Formattable::kInt64:
  78. if(Z_TYPE_P(args[i]) == IS_DOUBLE) {
  79. tInt64 = (int64_t)Z_DVAL_P(args[i]);
  80. } else if(Z_TYPE_P(args[i]) == IS_LONG) {
  81. tInt64 = (int64_t)Z_LVAL_P(args[i]);
  82. } else {
  83. SEPARATE_ZVAL_IF_NOT_REF(&args[i]);
  84. convert_scalar_to_number( args[i] TSRMLS_CC );
  85. tInt64 = (Z_TYPE_P(args[i]) == IS_DOUBLE)?(int64_t)Z_DVAL_P(args[i]):Z_LVAL_P(args[i]);
  86. }
  87. fargs[i].setInt64(tInt64);
  88. break;
  89. case Formattable::kString:
  90. convert_to_string_ex(&args[i]);
  91. intl_convert_utf8_to_utf16(&stringVal, &stringLen, Z_STRVAL_P(args[i]), Z_STRLEN_P(args[i]), status);
  92. if(U_FAILURE(*status)){
  93. delete[] fargs;
  94. return;
  95. }
  96. fargs[i].setString(stringVal);
  97. efree(stringVal);
  98. break;
  99. case Formattable::kArray:
  100. case Formattable::kObject:
  101. *status = U_UNSUPPORTED_ERROR;
  102. delete[] fargs;
  103. return;
  104. }
  105. }
  106. UnicodeString resultStr;
  107. FieldPosition fieldPosition(0);
  108. /* format the message */
  109. ((const MessageFormat*)fmt)->format(fargs, fmt_count, resultStr, fieldPosition, *status);
  110. delete[] fargs;
  111. if(U_FAILURE(*status)){
  112. return;
  113. }
  114. *formatted_len = resultStr.length();
  115. *formatted = eumalloc(*formatted_len+1);
  116. resultStr.extract(*formatted, *formatted_len+1, *status);
  117. }
  118. #define cleanup_zvals() for(int j=i;j>=0;j--) { zval_ptr_dtor((*args)+i); }
  119. U_CFUNC void umsg_parse_helper(UMessageFormat *fmt, int *count, zval ***args, UChar *source, int source_len, UErrorCode *status)
  120. {
  121. UnicodeString srcString(source, source_len);
  122. Formattable *fargs = ((const MessageFormat*)fmt)->parse(srcString, *count, *status);
  123. if(U_FAILURE(*status)) {
  124. return;
  125. }
  126. *args = (zval **)safe_emalloc(*count, sizeof(zval *), 0);
  127. // assign formattables to varargs
  128. for(int32_t i = 0; i < *count; i++) {
  129. int64_t aInt64;
  130. double aDate;
  131. UnicodeString temp;
  132. char *stmp;
  133. int stmp_len;
  134. ALLOC_INIT_ZVAL((*args)[i]);
  135. switch(fargs[i].getType()) {
  136. case Formattable::kDate:
  137. aDate = ((double)fargs[i].getDate())/U_MILLIS_PER_SECOND;
  138. if(aDate > LONG_MAX || aDate < -LONG_MAX) {
  139. ZVAL_DOUBLE((*args)[i], aDate<0?ceil(aDate):floor(aDate));
  140. } else {
  141. ZVAL_LONG((*args)[i], (long)aDate);
  142. }
  143. break;
  144. case Formattable::kDouble:
  145. ZVAL_DOUBLE((*args)[i], (double)fargs[i].getDouble());
  146. break;
  147. case Formattable::kLong:
  148. ZVAL_LONG((*args)[i], fargs[i].getLong());
  149. break;
  150. case Formattable::kInt64:
  151. aInt64 = fargs[i].getInt64();
  152. if(aInt64 > LONG_MAX || aInt64 < -LONG_MAX) {
  153. ZVAL_DOUBLE((*args)[i], (double)aInt64);
  154. } else {
  155. ZVAL_LONG((*args)[i], (long)aInt64);
  156. }
  157. break;
  158. case Formattable::kString:
  159. fargs[i].getString(temp);
  160. intl_convert_utf16_to_utf8(&stmp, &stmp_len, temp.getBuffer(), temp.length(), status);
  161. if(U_FAILURE(*status)) {
  162. cleanup_zvals();
  163. return;
  164. }
  165. ZVAL_STRINGL((*args)[i], stmp, stmp_len, 0);
  166. break;
  167. case Formattable::kObject:
  168. case Formattable::kArray:
  169. *status = U_ILLEGAL_ARGUMENT_ERROR;
  170. cleanup_zvals();
  171. break;
  172. }
  173. }
  174. delete[] fargs;
  175. }
  176. /*
  177. * Local variables:
  178. * tab-width: 4
  179. * c-basic-offset: 4
  180. * End:
  181. * vim600: noet sw=4 ts=4 fdm=marker
  182. * vim<600: noet sw=4 ts=4
  183. */