/src/sendanor/convert.h

https://github.com/jheusala/openjs · C Header · 335 lines · 206 code · 65 blank · 64 comment · 11 complexity · a282ba40244cf1065c79ef596aabda52 MD5 · raw file

  1. /* Convert everything to everything -- Specifically strings without removing locales charsets.
  2. * $Id: convert.h 10128 2009-11-17 11:06:08Z jheusala $
  3. */
  4. #ifndef SENDANOR_CONVERT_H
  5. #define SENDANOR_CONVERT_H
  6. #include <ostream> // for std::ostream
  7. #include <string> // for std::string
  8. #include <locale> // for std::locale
  9. #include <boost/lexical_cast.hpp> // for boost::lexical_cast
  10. #include <list> // for std::list
  11. #include "ScopedLocale.h" // for Sendanor::System::ScopedLocale
  12. #ifdef USE_GLIB
  13. #include <glibmm/ustring.h> // for Glib::ustring
  14. #endif // USE_GLIB
  15. #ifdef USE_V8
  16. #include <v8/v8.h> // for v8::*
  17. #endif // USE_V8
  18. #include "logger.h" // for SENDANOR_LOGGER_FUNCTION
  19. namespace sendanor {
  20. /** Convert T object to R type. Default specialization. */
  21. template<class R, class T>
  22. inline R convert(const T& value);
  23. /** Convert std::wstring to std::string and preserve charset. It means that
  24. * std::string will contain UTF-8 when user's locale has suitable codecvt.
  25. */
  26. extern inline std::wstring do_string_convert_to_wstring(const std::string& tmp, const std::locale& loc);
  27. /** Convert std::string to std::wstring and preserve charset. It means that
  28. * when user's locale has suitable codecvt, then std::string that has UTF-8
  29. * characters will be converted correctly to std::wstring.
  30. */
  31. extern inline std::string do_wstring_convert_to_string(const std::wstring& tmp, const std::locale& loc);
  32. /** Convert std::wstring to std::string and preserve charset. It means that
  33. * std::string will contain UTF-8 when user's locale has suitable codecvt.
  34. */
  35. template<>
  36. inline std::string convert<std::string, std::wstring >(const std::wstring& value) {
  37. SENDANOR_LOGGER_FUNCTION("convert<std::string, std::wstring >", "value");
  38. return do_wstring_convert_to_string(value, std::locale(""));
  39. }
  40. /** Convert std::string to std::wstring and preserve charset. It means that
  41. * when user's locale has suitable codecvt, then std::string that has UTF-8
  42. * characters will be converted correctly to std::wstring.
  43. */
  44. template<>
  45. inline std::wstring convert<std::wstring, std::string>(const std::string& value) {
  46. SENDANOR_LOGGER_FUNCTION("convert<std::wstring, std::string>", "value");
  47. return do_string_convert_to_wstring(value, std::locale(""));
  48. }
  49. /* Include Glib code if USE_GLIB is set */
  50. #ifdef USE_GLIB
  51. /** Convert std::string to Glib::ustring and preserve charset. It uses user's prevered locale. */
  52. extern inline Glib::ustring do_string_convert_to_ustring(const std::string& value);
  53. /** Convert Glib::ustring to std::string and preserve charset. It uses user's prevered locale. */
  54. extern inline std::string do_ustring_convert_to_string(const Glib::ustring& value);
  55. /** Convert Glib::ustring to std::string and preserve charset. It uses user's prevered locale. */
  56. template<>
  57. inline std::string convert<std::string, Glib::ustring >(const Glib::ustring& value) {
  58. SENDANOR_LOGGER_FUNCTION("convert<std::string, Glib::ustring >", "value");
  59. return do_ustring_convert_to_string(value);
  60. }
  61. /** Convert std::string to Glib::ustring and preserve charset. It uses user's prevered locale. */
  62. template<>
  63. inline Glib::ustring convert<Glib::ustring, std::string>(const std::string& value) {
  64. SENDANOR_LOGGER_FUNCTION("convert<Glib::ustring, std::string>", "value");
  65. return do_string_convert_to_ustring(value);
  66. }
  67. #endif // USE_GLIB
  68. /* Include Google V8 code if USE_V8 is set */
  69. #ifdef USE_V8
  70. extern inline std::string do_v8_convert_to_string(v8::Handle<v8::Value> value);
  71. extern inline std::wstring do_v8_convert_to_wstring(v8::Handle<v8::Value> value);
  72. extern inline v8::Handle<v8::Value> do_string_convert_to_v8(const std::string& value);
  73. /** Convert v8string to string */
  74. template<>
  75. inline std::string convert<std::string, v8::Handle<v8::Value> >(const v8::Handle<v8::Value>& value) {
  76. SENDANOR_LOGGER_FUNCTION("convert<std::string,v8::Handle<v8::Value>>", "value");
  77. return do_v8_convert_to_string(value);
  78. }
  79. /** Convert v8string to string */
  80. template<>
  81. inline std::string convert<std::string, v8::Local<v8::Value> >(const v8::Local<v8::Value>& value) {
  82. SENDANOR_LOGGER_FUNCTION("convert<std::string,v8::Local<v8::Value>>", "value");
  83. return do_v8_convert_to_string(value);
  84. }
  85. /** Convert string to v8string */
  86. template<>
  87. inline v8::Handle<v8::Value> convert<v8::Handle<v8::Value>, std::string>(const std::string& value) {
  88. SENDANOR_LOGGER_FUNCTION("convert<v8::Handle<v8::Value>,std::string>", "value");
  89. return do_string_convert_to_v8(value);
  90. }
  91. /* Include Glib code if USE_GLIB is not set */
  92. #ifdef USE_GLIB
  93. extern inline Glib::ustring do_v8_convert_to_ustring(v8::Handle<v8::Value> value);
  94. extern inline v8::Handle<v8::Value> do_ustring_convert_to_v8(const Glib::ustring& value);
  95. /** Convert v8string to ustring */
  96. template<>
  97. inline Glib::ustring convert<Glib::ustring, v8::Handle<v8::Value> >(const v8::Handle<v8::Value>& value) {
  98. SENDANOR_LOGGER_FUNCTION("convert<Glib::ustring,v8::Handle<v8::Value>>", "value");
  99. return do_v8_convert_to_ustring(value);
  100. }
  101. /** Convert v8string to ustring */
  102. template<>
  103. inline Glib::ustring convert<Glib::ustring, v8::Local<v8::Value> >(const v8::Local<v8::Value>& value) {
  104. SENDANOR_LOGGER_FUNCTION("convert<Glib::ustring,v8::Local<v8::Value>>", "value");
  105. return do_v8_convert_to_ustring(value);
  106. }
  107. /** Convert ustring to v8string */
  108. template<>
  109. inline v8::Handle<v8::Value> convert<v8::Handle<v8::Value>, Glib::ustring>(const Glib::ustring& value) {
  110. SENDANOR_LOGGER_FUNCTION("convert<v8::Handle<v8::Value>,std::string>", "value");
  111. return do_ustring_convert_to_v8(value);
  112. }
  113. #endif // USE_GLIB
  114. #endif // USE_V8
  115. }
  116. /** The source implementation */
  117. //#include <iostream> // for std::cerr
  118. #include <fstream> // for std::fstream
  119. #include <cstdlib> //
  120. #include <vector> // for std::vector
  121. #include <sstream> // for std::ostringstream
  122. #include "exception.h" // for RUNTIME_ERROR
  123. #include <boost/iostreams/stream.hpp> // for boost::iostreams::stream
  124. #include <boost/iostreams/code_converter.hpp> // for boost::iostreams::code_converter
  125. #include <boost/iostreams/device/array.hpp> // for boost::iostreams::array_source
  126. #include <boost/iostreams/device/back_inserter.hpp> // for boost::iostreams::back_insert_device
  127. #include <cwchar> // for std::mbstate_t
  128. #ifdef USE_GLIB
  129. #include <glibmm/convert.h> // for Glib::locale_to_utf8
  130. #endif // USE_GLIB
  131. #ifdef USE_V8
  132. #include <v8/v8.h> // for v8::*
  133. #endif // USE_V8
  134. #include "logger.h" // for SENDANOR_LOGGER_DEBUG
  135. /* String to wstring conversion */
  136. inline std::wstring sendanor::do_string_convert_to_wstring(const std::string& tmp, const std::locale& loc) {
  137. SENDANOR_LOGGER_FUNCTION("do_string_convert_to_wstring", "tmp, loc=`" << loc.name() << "'" );
  138. // Check codecvt facet
  139. if(std::has_facet< std::codecvt<wchar_t, char, std::mbstate_t> >(loc)) {
  140. SENDANOR_LOGGER_DEBUG("convert: codecvt support");
  141. boost::iostreams::stream<boost::iostreams::code_converter<boost::iostreams::array_source> > in(tmp.c_str(), tmp.size());
  142. in.imbue(loc);
  143. std::wstring buf;
  144. wchar_t ch;
  145. while(in.get(ch)) buf += ch;
  146. return buf;
  147. }
  148. // Check for widen support
  149. if(std::has_facet< std::ctype<wchar_t> >(loc)) {
  150. SENDANOR_LOGGER_DEBUG("convert: ctype support");
  151. std::wstring buf;
  152. for(std::string::const_iterator i = tmp.begin(); i!=tmp.end(); ++i) {
  153. buf += std::use_facet< std::ctype<wchar_t> >(loc).widen(*i);
  154. }
  155. return buf;
  156. }
  157. // Unknown case
  158. throw RUNTIME_ERROR("Cannot convert: unimplemented case.");
  159. }
  160. /** Specialization for wstring to string conversion */
  161. inline std::string sendanor::do_wstring_convert_to_string(const std::wstring& tmp, const std::locale& loc) {
  162. SENDANOR_LOGGER_FUNCTION("do_wstring_convert_to_string", "tmp, loc=`" << loc.name() << "'" );
  163. // Check for codecvt support
  164. if(std::has_facet< std::codecvt<wchar_t, char, std::mbstate_t> >(loc)) {
  165. SENDANOR_LOGGER_DEBUG("convert: codecvt support");
  166. typedef boost::iostreams::code_converter<boost::iostreams::back_insert_device<std::string> > code_converter;
  167. std::string buffer;
  168. { // We need to call out's destructor before we use buffer
  169. boost::iostreams::stream<code_converter> out(buffer);
  170. out.imbue(loc);
  171. out << tmp;
  172. }
  173. return buffer;
  174. }
  175. // Check for narrow support
  176. if(std::has_facet< std::ctype<wchar_t> >(loc)) {
  177. SENDANOR_LOGGER_DEBUG("convert: ctype support");
  178. std::string buf;
  179. for(std::wstring::const_iterator i = tmp.begin(); i!=tmp.end(); ++i) {
  180. buf += std::use_facet< std::ctype<wchar_t> >(loc).narrow(*i, '?');
  181. }
  182. return buf;
  183. }
  184. // Unknown case
  185. throw RUNTIME_ERROR("Cannot convert: unimplemented case.");
  186. }
  187. /* Include code for Glib::ustring if USE_GLIB is set */
  188. #ifdef USE_GLIB
  189. /** Convert ustring to string with UTF-8, using user's current locale */
  190. inline std::string sendanor::do_ustring_convert_to_string(const Glib::ustring& value) {
  191. SENDANOR_LOGGER_FUNCTION("do_ustring_convert_to_string", "value" );
  192. //std::locale loc("");
  193. const std::string strbuf = Glib::locale_from_utf8(value);
  194. //const std::string strbuf = Glib::convert(value.str(), "UTF-8", "UTF-8");
  195. //const std::string strbuf = value.raw();
  196. SENDANOR_LOGGER_DEBUG("strbuf=`" << strbuf << "'");
  197. return strbuf;
  198. }
  199. /** Convert string with UTF-8 to ustring, usign user's current locale */
  200. inline Glib::ustring sendanor::do_string_convert_to_ustring(const std::string& value) {
  201. SENDANOR_LOGGER_FUNCTION("do_string_convert_to_ustring", "value" );
  202. //std::locale loc("");
  203. const Glib::ustring buf = Glib::locale_to_utf8(value);
  204. //const Glib::ustring buf = Glib::convert(value, "UTF-8", "UTF-8");
  205. SENDANOR_LOGGER_DEBUG("buf=`" << buf << "'");
  206. return buf;
  207. }
  208. #endif // USE_GLIB
  209. /* Include code for Google's V8 strings if USE_V8 is set */
  210. #ifdef USE_V8
  211. #ifdef USE_GLIB
  212. /** */
  213. inline Glib::ustring sendanor::do_v8_convert_to_ustring(v8::Handle<v8::Value> value) {
  214. SENDANOR_LOGGER_FUNCTION("do_v8_convert_to_ustring", "value(v8)" );
  215. const std::string strbuf = sendanor::do_v8_convert_to_string(value);
  216. SENDANOR_LOGGER_DEBUG("strbuf=`" << strbuf << "'");
  217. const Glib::ustring buf = sendanor::do_string_convert_to_ustring(strbuf);
  218. SENDANOR_LOGGER_DEBUG("buf=`" << buf << "'");
  219. return buf;
  220. }
  221. /** */
  222. inline v8::Handle<v8::Value> sendanor::do_ustring_convert_to_v8(const Glib::ustring& value) {
  223. SENDANOR_LOGGER_FUNCTION("do_ustring_convert_to_v8", "value" );
  224. const std::string strbuf = sendanor::do_ustring_convert_to_string(value);
  225. SENDANOR_LOGGER_DEBUG("strbuf=`" << strbuf << "'");
  226. v8::Handle<v8::Value> ret = sendanor::do_string_convert_to_v8(strbuf);
  227. const std::string strbuf2 = sendanor::do_v8_convert_to_string(ret);
  228. SENDANOR_LOGGER_DEBUG("strbuf2=`" << strbuf2 << "'");
  229. if(strbuf != strbuf2) throw RUNTIME_ERROR("strbuf != strbuf2");
  230. return ret;
  231. }
  232. #endif // USE_GLIB
  233. /** Convert v8 string to 16-bit std::wstring
  234. */
  235. inline std::wstring sendanor::do_v8_convert_to_wstring(v8::Handle<v8::Value> value) {
  236. SENDANOR_LOGGER_FUNCTION("do_v8_convert_to_wstring", "value(v8)" );
  237. v8::Local<v8::String> tmp = value->ToString();
  238. v8::String::Value int16value(tmp);
  239. uint16_t* uintbuf = *int16value;
  240. if(sizeof(uint16_t) > sizeof(wchar_t)) throw LOGIC_ERROR("sizeof(uint16_t) > sizeof(wchar_t) !");
  241. std::wstring wstrbuf;
  242. for(int i=0; i<int16value.length(); ++i) {
  243. wstrbuf += uintbuf[i];
  244. }
  245. return wstrbuf;
  246. //std::string strbuf = do_wstring_convert_to_string(wstrbuf, std::locale() );
  247. //SENDANOR_LOGGER_DEBUG("strbuf=`" << strbuf << "'");
  248. //return strbuf;
  249. }
  250. /** Convert v8 string to UTF-8 std::string */
  251. inline std::string sendanor::do_v8_convert_to_string(v8::Handle<v8::Value> value) {
  252. SENDANOR_LOGGER_FUNCTION("do_v8_convert_to_string", "value(v8)" );
  253. v8::Local<v8::String> tmp = value->ToString();
  254. v8::String::Utf8Value uvalue(tmp);
  255. std::string strbuf( *uvalue, uvalue.length() );
  256. SENDANOR_LOGGER_DEBUG("strbuf=`" << strbuf << "'");
  257. return strbuf;
  258. }
  259. /** Convert UTF-8 std::string to v8 data type */
  260. inline v8::Handle<v8::Value> sendanor::do_string_convert_to_v8(const std::string& value) {
  261. SENDANOR_LOGGER_FUNCTION("do_string_convert_to_v8", "value" );
  262. return v8::String::New(value.c_str(), value.size());
  263. //const std::string strbuf2 = sendanor::do_v8_convert_to_string(ret);
  264. //SENDANOR_LOGGER_DEBUG("strbuf2=`" << strbuf2 << "'");
  265. //if(value != strbuf2) throw RUNTIME_ERROR("strbuf != strbuf2");
  266. //return ret;
  267. }
  268. #endif // USE_V8
  269. #endif // SENDANOR_CONVERT_H
  270. /* EOF */