]> git.sesse.net Git - ccbs/blobdiff - bigscreen/widestring.cpp
Shape text using Pango and HarfBuzz; gives us nice ligatures and exotic scripts.
[ccbs] / bigscreen / widestring.cpp
index 9193586379e63b7474ed9f57df0826aeb214b1be..f486aaec8dde5e9b5ec96a811324ed92839aa1d8 100644 (file)
@@ -1,12 +1,30 @@
+#include <stdlib.h>
+#include <cstring>
 #include <iconv.h>
 #include <endian.h>
 #include <exception>
 #include <pqxx/util>
 #include "widestring.h"
 
-static iconv_t ucs4_iconv;
+static iconv_t ucs4_iconv, ucs4_reverse_iconv;
 static bool iconv_initialized = false;
 
+void ensure_iconv_initialized()
+{
+       if (iconv_initialized) {
+               return;
+       }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+       ucs4_iconv = iconv_open("ucs-4le", "utf-8");
+       ucs4_reverse_iconv = iconv_open("utf-8", "ucs-4le");
+#else
+       ucs4_iconv = iconv_open("ucs-4be", "utf-8");
+       ucs4_reverse_iconv = iconv_open("utf-8", "ucs-4be");
+#endif
+
+       iconv_initialized = true;
+}
+
 widestring::widestring()
 {
 }
@@ -16,17 +34,19 @@ widestring::widestring(const char *from)
        *this = from;
 }
 
-void widestring::operator= (const char *from)
+widestring::widestring(const std::string &from)
 {
-       if (!iconv_initialized) {
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-               ucs4_iconv = iconv_open("ucs-4le", "utf-8");
-#else
-               ucs4_iconv = iconv_open("ucs-4be", "utf-8");
-#endif
+       *this = from.c_str();
+}
 
-               iconv_initialized = true;
-       }
+widestring::widestring(const std::wstring &from)
+       : std::wstring(from)
+{
+}
+
+void widestring::operator= (const char *from)
+{
+       ensure_iconv_initialized();
        
        unsigned bytes = std::strlen(from);
        char *from_buf = strdup(from);
@@ -55,9 +75,34 @@ void widestring::operator= (const char *from)
        delete[] to_buf;
 }
 
-template<>
-void pqxx::from_string<widestring>(const char *from, widestring &to)
+std::string widestring::to_utf8() const
 {
-       to = from;
-}
+       ensure_iconv_initialized();
+
+       wchar_t *from_buf = wcsdup(c_str());
+       size_t out_max_size = size() * 6;
+       char *to_buf = new char[out_max_size];
+
+       char *inptr = reinterpret_cast<char *>(from_buf), *outptr = to_buf;
+
+       size_t in_left = size() * sizeof(wchar_t);
+       size_t out_left = out_max_size;
+
+       size_t ret = iconv(ucs4_reverse_iconv, NULL, NULL, &outptr, &out_left);
+       if (ret == (size_t)(-1)) {
+               throw std::runtime_error("Error in iconv during initialization");
+       }
+
+       ret = iconv(ucs4_reverse_iconv, &inptr, &in_left, &outptr, &out_left);
+       if (ret == (size_t)(-1)) {
+               perror("iconv");
+               throw std::runtime_error("Error in iconv during conversion");
+       }
+
+       std::string utf8(to_buf, outptr);
 
+       free(from_buf);
+       delete[] to_buf;
+
+       return utf8;
+}