xx 2 lat temu
rodzic
commit
3a8ebca084

+ 1 - 1
CMakeLists.txt

@@ -58,7 +58,7 @@ add_subdirectory(src/yutil)
 add_subdirectory(src/yqt)
 add_subdirectory(src/yqt)
 add_subdirectory(src/ynet)
 add_subdirectory(src/ynet)
 add_subdirectory(src/yqlua)
 add_subdirectory(src/yqlua)
-add_subdirectory(src/ymysql)
+add_subdirectory(src/ysql)
 ########################  三方库  ########################
 ########################  三方库  ########################
 add_subdirectory(3rdparty/zlib)
 add_subdirectory(3rdparty/zlib)
 add_subdirectory(3rdparty/lua)
 add_subdirectory(3rdparty/lua)

+ 1 - 0
include/ybase/buffer.h

@@ -41,6 +41,7 @@ public:
     ~buffer();
     ~buffer();
     void set(const char* data, size_t length);
     void set(const char* data, size_t length);
     void set(const ylib::buffer& data);
     void set(const ylib::buffer& data);
+    void append(const std::string& data);
     void append(const char* data, size_t length);
     void append(const char* data, size_t length);
     void append(const ylib::buffer& data);
     void append(const ylib::buffer& data);
     void append(std::initializer_list<uchar> char_list);
     void append(std::initializer_list<uchar> char_list);

+ 19 - 12
include/ynet/http_cookie.h

@@ -2,19 +2,26 @@
 #include "http_define.h"
 #include "http_define.h"
 #if USE_NET_HTTP_UTIL
 #if USE_NET_HTTP_UTIL
 #include <map>
 #include <map>
-namespace ylib::network::http
+namespace ylib
 {
 {
-    class cookie
+    namespace network
     {
     {
-    public:
-        cookie();
-        ~cookie();
-        void merge(const cookie& ck);
-        void merge(const std::string& ck);
-        std::string to_string();
-        void clear();
-    private:
-        std::map<std::string, std::string> m_param;
-    };
+        namespace http
+        {
+            class cookie
+            {
+            public:
+                cookie();
+                ~cookie();
+                void merge(const cookie& ck);
+                void merge(const std::string& ck);
+                std::string to_string();
+                void clear();
+            private:
+                std::map<std::string, std::string> m_param;
+            };
+        }
+    }
+   
 }
 }
 #endif
 #endif

+ 127 - 0
include/ysql/mssql.h

@@ -0,0 +1,127 @@
+#pragma once
+#ifdef _WIN32
+#include <vector>
+#include <string>
+#include <list>
+#ifndef _WIN32
+#include <stddef.h>
+#endif
+#include "ybase/define.h"
+#include "ybase/error.h"
+#include "yutil/json.h"
+#include "yutil/pool.hpp"
+
+namespace ylib::mssql
+{
+    class pool;
+    class result;
+    class conn;
+    class prepare_statement;
+    struct mssql_conn_info
+    {
+        mssql_conn_info(){
+        }
+        std::string odbcname;
+        std::string username;
+        std::string password;
+    };
+    class result :public ylib::error_base
+    {
+    public:
+        result();
+        ~result();
+        // 列数量
+        uint32 field_count();
+        // 行数量
+        size_t row_count();
+        // 取文本值
+        std::string get(uint32 field);
+        // 下一行
+        bool next();
+        int32 get_int32(uint32 index);
+        int32 get_int32(const std::string& name);
+
+        uint32 get_uint32(uint32 index);
+        uint32 get_uint32(const std::string& name);
+
+        int64 get_int64(uint32 index);
+        int64 get_int64(const std::string& name);
+
+        uint64 get_uint64(uint32 index);
+        uint64 get_uint64(const std::string& name);
+
+        std::string get_string(uint32 index);
+        std::string get_string(const std::string& name);
+
+        bool get_boolean(uint32 index);
+        bool get_boolean(const std::string& name);
+
+        double get_double(uint32 index);
+        double get_double(const std::string& name);
+
+        friend class ylib::mssql::prepare_statement;
+    private:
+        void* m_handle = nullptr;
+        uint32 m_field_count = 0;
+        uint32 m_row_count = 0;
+
+        std::map<std::string, short> m_field_name_index;
+    };
+
+    class prepare_statement:public ylib::error_base{
+    public:
+        prepare_statement();
+        ~prepare_statement();
+        void set_boolean(uint32 index,bool value);
+        void set_datetime(uint32 index,const std::string& value);
+        void set_double(uint32 index,double value);
+        void set_int32(uint32 index,int32 value);
+        void set_uint32(uint32 index,uint32 value);
+        void set_int64(uint32 index,int64 value);
+        void set_uint64(uint32 index,uint64 value);
+        void set_null(uint32 index);
+        void set_string(uint32 index,const std::string& value);
+        void clear();
+        uint64 update();
+        ylib::mssql::result* query();
+
+        friend class ylib::mssql::conn;
+    private:
+        ylib::mssql::result* m_result = nullptr;
+        void* m_handle = nullptr;
+    };
+    class conn :public ylib::example<ylib::mssql::mssql_conn_info>,public ylib::error_base
+    {
+    public:
+        conn();
+        ~conn();
+        virtual EXAMPLE_START_RESULT start(const ylib::mssql::mssql_conn_info&info) override;
+        virtual void close() override;
+
+
+        virtual void recover() override;
+        virtual void task_out() override;
+
+
+        void clear();
+        ylib::mssql::prepare_statement* setsql(const std::string& sql);
+        void begin();
+        void commit();
+        void rollback();
+        friend class ylib::mssql::pool;
+    private:
+        void *m_handle = nullptr;
+        ylib::mssql::mssql_conn_info m_info;
+        class prepare_statement* m_ppst = nullptr;
+        int m_sw = 0;
+    };
+
+
+    class pool: public ylib::pool<ylib::mssql::conn, ylib::mssql::mssql_conn_info>
+    {
+    public:
+        pool();
+        ~pool();
+    };
+}
+#endif

+ 0 - 0
include/ymysql/mysql_plus.h → include/ysql/mysql.h


+ 1 - 1
include/yutil/counter.hpp

@@ -6,7 +6,7 @@ namespace  ylib {
     public:
     public:
         counter(const T& default_value = 0){m_value = default_value;}
         counter(const T& default_value = 0){m_value = default_value;}
         ~counter() {}
         ~counter() {}
-        size_t make(){
+        T make(){
             std::unique_lock<std::mutex> guard(m_mutex);
             std::unique_lock<std::mutex> guard(m_mutex);
             return ++m_value;
             return ++m_value;
         }
         }

+ 5 - 1
include/yutil/debug.h

@@ -1,10 +1,14 @@
 #pragma once
 #pragma once
-
+#include <string>
 namespace ylib
 namespace ylib
 {
 {
 	namespace debug
 	namespace debug
 	{
 	{
 		// 检测异常产生DUMP文件
 		// 检测异常产生DUMP文件
 		void detect_exception();
 		void detect_exception();
+#ifdef _WIN32
+		// 打印VS控制台
+		void vs_console_println(const std::string& value);
+#endif
 	}
 	}
 }
 }

+ 32 - 0
include/yutil/interval.hpp

@@ -0,0 +1,32 @@
+#pragma once
+#include <mutex>
+#include "yutil/time.h"
+namespace  ylib {
+    class interval {
+    public:
+        interval(timestamp msec):m_interval_msec(msec),m_pre_msec(0){
+            m_pre_msec = time::now_msec();
+        }
+        ~interval() {}
+        /// <summary>
+        /// 是否超市
+        /// </summary>
+        /// <returns></returns>
+        bool isTimeout() {
+            auto now_msec = time::now_msec();
+            if (m_pre_msec + m_interval_msec < now_msec)
+                return true;
+            return false;
+        }
+        void timeout() {
+            m_pre_msec = time::now_msec() - m_interval_msec - 1;
+        }
+        void update() {
+            m_pre_msec = time::now_msec();
+        }
+
+    private:
+        timestamp m_interval_msec = 0;
+        timestamp m_pre_msec = 0;
+    };
+}

+ 5 - 1
include/yutil/pool.hpp

@@ -29,6 +29,8 @@ namespace ylib {
             m_pop_size--;
             m_pop_size--;
             m_queue.push(example);
             m_queue.push(example);
         }
         }
+    public:
+        void* env = nullptr;
     protected:
     protected:
         ylib::queue<void*> m_queue;
         ylib::queue<void*> m_queue;
         std::mutex m_mutex;
         std::mutex m_mutex;
@@ -150,6 +152,8 @@ namespace ylib {
                 {
                 {
                     bool init_success = false;
                     bool init_success = false;
                     example = new EXAMPLE;
                     example = new EXAMPLE;
+                    //example->pool((void*)this);
+                    ((EXAMPLE*)example)->pool(this);
                     for (uint32 i = 0; i < 3; i++)
                     for (uint32 i = 0; i < 3; i++)
                     {
                     {
                         auto SR = ((EXAMPLE*)example)->start(m_info);
                         auto SR = ((EXAMPLE*)example)->start(m_info);
@@ -172,7 +176,7 @@ namespace ylib {
                     if (init_success)
                     if (init_success)
                     {
                     {
                         m_pop_size++;
                         m_pop_size++;
-                        ((EXAMPLE*)example)->pool(this);
+                       
                         ((EXAMPLE*)example)->task_out();
                         ((EXAMPLE*)example)->task_out();
                         return ((EXAMPLE*)example);
                         return ((EXAMPLE*)example);
                     }
                     }

+ 5 - 0
src/ybase/src/buffer.cpp

@@ -51,6 +51,11 @@ void ylib::buffer::set(const ylib::buffer& data)
     set((const char*)data.data(), data.length());
     set((const char*)data.data(), data.length());
 }
 }
 
 
+void ylib::buffer::append(const std::string& data)
+{
+    append(data.c_str(),data.length());
+}
+
 void ylib::buffer::append(const char* data, size_t length)
 void ylib::buffer::append(const char* data, size_t length)
 {
 {
     m_data.append((const uchar*)data,length);
     m_data.append((const uchar*)data,length);

+ 0 - 0
src/ymysql/CMakeLists.txt → src/ysql/CMakeLists.txt


+ 471 - 0
src/ysql/src/mssql.cpp

@@ -0,0 +1,471 @@
+#include "ysql/mssql.h"
+#ifdef _WIN32
+#include "yutil/time.h"
+#include <windows.h>
+#include <sql.h>
+#include <sqlext.h>
+#include "yutil/strutils.h"
+#define CHECK_SQL_CONNECTION if(m_handle == nullptr){throw ylib::exception("current connection is invalid");}
+#define CHECK_SQL_PPST if(m_handle == nullptr){throw ylib::exception("current preparedstatement is invalid");}
+#define CHECK_SQL_RESULT if(m_handle == nullptr){throw ylib::exception("current resultset is invalid");}
+
+#define THROW_RET(RESULT,MSG)                                                                                                               \
+    if (RESULT != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)                                                                                                      \
+    throw ylib::exception(MSG)              
+
+
+#define THROW_RET_BIND(RESULT)  THROW_RET(RESULT,"SQLBindParameter Failed,code: " + std::to_string(RESULT))
+#define THROW_RET_GET(RESULT)  THROW_RET(RESULT,"SQLGetData Failed,code: " + std::to_string(RESULT))
+
+
+
+ylib::mssql::conn::conn()
+{
+    m_handle = nullptr;
+    m_ppst = nullptr;
+}
+
+ylib::mssql::conn::~conn()
+{
+    close();
+}
+EXAMPLE_START_RESULT ylib::mssql::conn::start(const mssql_conn_info &info)
+{
+    if (info.odbcname.empty())
+    {
+        m_lastErrorDesc = "odbcname is empty";
+        return SR_FAILED;
+    }
+    m_info = info;
+    
+
+    SQLHDBC hDbc = nullptr;
+    SQLAllocHandle(SQL_HANDLE_DBC,  m_pool->env, &hDbc);
+    SQLCHAR connStr[1024];
+    sprintf((char*)connStr, "DSN=%s;UID=%s;PWD=%s;", m_info.odbcname.c_str(), m_info.username.c_str(), m_info.password.c_str());
+    SQLRETURN ret = SQLDriverConnect(hDbc, NULL, connStr, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
+    if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
+        // 连接失败
+        SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
+        return SR_FAILED;
+    }
+    m_handle = hDbc;
+    return SR_SUCCESS;
+}
+
+void ylib::mssql::conn::close()
+{
+    if (m_handle == nullptr)
+        return;
+    SQLDisconnect(m_handle);
+    SQLFreeHandle(SQL_HANDLE_DBC, m_handle);
+}
+
+void ylib::mssql::conn::recover()
+{
+    if (m_sw == 1)
+    {
+        rollback();
+    }
+    SQLSetConnectAttr(m_pool->env, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
+    clear();
+    
+}
+
+void ylib::mssql::conn::task_out()
+{
+
+}
+
+void ylib::mssql::conn::clear()
+{
+    if(this->m_ppst != nullptr)
+        delete this->m_ppst;
+
+    this->m_ppst = nullptr;
+}
+
+ylib::mssql::prepare_statement* ylib::mssql::conn::setsql(const std::string &sql)
+{
+    CHECK_SQL_CONNECTION;
+    clear();
+    m_ppst = new prepare_statement;
+    SQLAllocHandle(SQL_HANDLE_STMT, m_handle, &m_ppst->m_handle);
+    SQLPrepare(m_ppst->m_handle, (SQLCHAR*)sql.c_str(), SQL_NTS);
+    return m_ppst;
+}
+void ylib::mssql::conn::begin()
+{
+    CHECK_SQL_CONNECTION;
+    auto ret = SQLSetConnectAttr(m_handle, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, 0);
+    THROW_RET(ret,"SQLSetConnectAttr failed,code: "+std::to_string(ret));
+    m_sw = 1;
+}
+
+void ylib::mssql::conn::commit()
+{
+    auto ret = SQLTransact(m_pool->env, m_handle, SQL_COMMIT);
+    THROW_RET(ret, "SQLSetConnectAttr failed,code: " + std::to_string(ret));
+    m_sw = 0;
+}
+
+void ylib::mssql::conn::rollback()
+{
+    auto ret = SQLTransact(m_pool->env, m_handle, SQL_ROLLBACK);
+    THROW_RET(ret, "SQLTransact failed,code: " + std::to_string(ret));
+}
+ylib::mssql::prepare_statement::prepare_statement()
+{
+    m_result = nullptr;
+    m_handle = nullptr;
+}
+
+ylib::mssql::prepare_statement::~prepare_statement()
+{
+    clear();
+    if(m_handle != nullptr)
+    {
+        SQLFreeHandle(SQL_HANDLE_STMT, m_handle);
+        m_handle = nullptr;
+    }
+}
+#if 0
+#define PRINT_DEBUG_SET std::cout<<__FUNCTION__<<"["<<index<<"]: "<<value<<std::endl
+#define PRINT_DEBUG_SET_std::string std::cout<<__FUNCTION__<<"["<<index<<"]: "<<value.c_str()<<std::endl
+#else
+#define PRINT_DEBUG_SET
+#define PRINT_DEBUG_SET_NSTRING
+#endif
+
+
+
+void ylib::mssql::prepare_statement::set_boolean(uint32 index, bool value)
+{
+    CHECK_SQL_PPST;
+    PRINT_DEBUG_SET;
+
+    SQLLEN lenOrInd = 0;
+    auto ret = SQLBindParameter(m_handle, index, SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT, 0, 0, &value, 0, &lenOrInd);
+    THROW_RET_BIND(ret);
+}
+
+void ylib::mssql::prepare_statement::set_datetime(uint32 index, const std::string &value)
+{
+    auto sec = time::to_ts(value);
+    ylib::time::datetime dt;
+    time::format(sec, dt);
+    
+    SQL_TIMESTAMP_STRUCT mssdt;
+    mssdt.year = dt.year;
+    mssdt.month = dt.month;
+    mssdt.day = dt.day;
+    mssdt.hour = dt.hour;
+    mssdt.minute = dt.minute;
+    mssdt.second = dt.second;
+    mssdt.fraction = 0;
+    SQLLEN lenOrInd = 0;
+    auto ret = SQLBindParameter(m_handle, index, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TIMESTAMP, 0, 0, &mssdt, 0, &lenOrInd);
+    THROW_RET_BIND(ret);
+}
+
+void ylib::mssql::prepare_statement::set_double(uint32 index, double value)
+{
+    CHECK_SQL_PPST;
+    PRINT_DEBUG_SET;
+
+    SQLLEN lenOrInd = 0;
+    auto ret = SQLBindParameter(m_handle, index, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &value, 0, &lenOrInd);
+    THROW_RET_BIND(ret);
+}
+
+void ylib::mssql::prepare_statement::set_int32(uint32 index, int32 value)
+{
+    CHECK_SQL_PPST;
+    PRINT_DEBUG_SET;
+    SQLLEN lenOrInd = 0;
+
+    auto ret = SQLBindParameter(m_handle, index, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &value, 0, &lenOrInd);
+    THROW_RET_BIND(ret);
+}
+
+void ylib::mssql::prepare_statement::set_uint32(uint32 index, uint32 value)
+{
+    CHECK_SQL_PPST;
+    PRINT_DEBUG_SET;
+    
+
+    SQLLEN lenOrInd = 0;
+    auto ret = SQLBindParameter(m_handle, index, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &value, 0, &lenOrInd);
+    THROW_RET_BIND(ret);
+}
+
+void ylib::mssql::prepare_statement::set_int64(uint32 index, int64 value)
+{
+    CHECK_SQL_PPST;
+    PRINT_DEBUG_SET;
+    
+    SQLLEN lenOrInd = 0;
+
+    auto ret = SQLBindParameter(m_handle, index, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 0, 0, &value, 0, &lenOrInd);
+    THROW_RET_BIND(ret);
+}
+
+void ylib::mssql::prepare_statement::set_uint64(uint32 index, uint64 value)
+{
+    CHECK_SQL_PPST;
+    PRINT_DEBUG_SET;
+    
+    SQLLEN lenOrInd = 0;
+    auto ret = SQLBindParameter(m_handle, index, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_BIGINT, 0, 0, &value, 0, &lenOrInd);
+    THROW_RET_BIND(ret);
+}
+
+void ylib::mssql::prepare_statement::set_null(uint32 index)
+{
+    //throw ylib::exception("Not supported temporarily");
+    
+    SQLLEN lenOrInd = SQL_NULL_DATA;
+    auto ret = SQLBindParameter(m_handle, index, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, NULL, 0, &lenOrInd);
+    THROW_RET_BIND(ret);
+}
+
+void ylib::mssql::prepare_statement::set_string(uint32 index, const std::string &value)
+{
+    CHECK_SQL_PPST;
+    PRINT_DEBUG_SET_NSTRING;
+    
+    SQLLEN lenOrInd = SQL_NTS;  // SQL_NTS denotes string is null-terminated
+
+    auto ret = SQLBindParameter(m_handle, index, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, value.length(), 0, (void*)value.c_str(), 0, &lenOrInd);
+
+    THROW_RET_BIND(ret);
+
+}
+void ylib::mssql::prepare_statement::clear()
+{
+    if(m_result != nullptr)
+    {
+        delete m_result;
+    }
+    m_result = nullptr;
+}
+
+uint64 ylib::mssql::prepare_statement::update()
+{
+    CHECK_SQL_PPST;
+    clear();
+    auto ret = SQLExecute(m_handle);
+    THROW_RET(ret,"SQLExecute failed,code: "+std::to_string(ret));
+    SQLLEN numRowsAffected = 0;
+    ret = SQLRowCount(m_handle, &numRowsAffected);
+    THROW_RET(ret, "SQLRowCount failed,code: " + std::to_string(ret));
+    return numRowsAffected;
+}
+
+ylib::mssql::result *ylib::mssql::prepare_statement::query()
+{
+    CHECK_SQL_PPST;
+    clear();
+    auto ret = SQLExecute(m_handle);
+    THROW_RET(ret, "SQLExecute failed,code: " + std::to_string(ret));
+    
+    m_result = new ylib::mssql::result();
+    m_result->m_handle = m_handle;
+
+    // 列数量
+    {
+        short num = 0;
+        auto ret = SQLNumResultCols(m_handle, &num);
+        THROW_RET(ret, "SQLNumResultCols failed,code: " + std::to_string(ret));
+        m_result->m_field_count = num;
+    }
+    // 行数量
+    {
+        SQLLEN numRowsAffected = 0;
+        auto ret = SQLRowCount(m_handle, &numRowsAffected);
+        THROW_RET(ret, "SQLRowCount failed,code: " + std::to_string(ret));
+        m_result->m_row_count = numRowsAffected;
+    }
+    // 列名称对应索引位置
+    {
+        SQLCHAR colName[128];
+        SQLSMALLINT colNameLen;
+        SQLSMALLINT dataType;
+        SQLULEN columnSize;
+        SQLSMALLINT decimalDigits;
+        SQLSMALLINT nullable;
+        SQLRETURN ret;
+        SQLSMALLINT targetCol = 0;  // 目标列的索引
+        for (SQLSMALLINT i = 1; i <= m_result->m_field_count; i++) {
+            ret = SQLDescribeCol(m_handle, i, colName, sizeof(colName), &colNameLen, &dataType, &columnSize, &decimalDigits, &nullable);
+            if (SQL_SUCCEEDED(ret)) {
+                m_result->m_field_name_index[reinterpret_cast<char*>(colName)] = i;
+            }
+        }
+    }
+    return m_result;
+}
+
+ylib::mssql::result::result()
+{
+    m_handle = nullptr;
+}
+
+ylib::mssql::result::~result()
+{
+    if(m_handle != nullptr)
+    {
+        m_handle = nullptr;
+    }
+}
+
+uint32 ylib::mssql::result::field_count()
+{
+    return m_field_count;
+}
+
+size_t ylib::mssql::result::row_count()
+{
+    return m_row_count;
+}
+
+bool ylib::mssql::result::next()
+{
+    CHECK_SQL_PPST;
+    return SQLFetch(m_handle) == SQL_SUCCESS;
+}
+
+int32 ylib::mssql::result::get_int32(uint32 index)
+{
+    CHECK_SQL_PPST;
+    SQLINTEGER value;
+    SQLLEN length_or_indicator;
+    auto ret = SQLGetData(m_handle, 1, SQL_C_SLONG, &value, sizeof(value), &length_or_indicator);
+    THROW_RET_GET(ret);
+    return value;
+}
+
+int32 ylib::mssql::result::get_int32(const std::string &name)
+{
+    return get_int32(m_field_name_index[name]);
+}
+
+uint32 ylib::mssql::result::get_uint32(uint32 index)
+{
+    CHECK_SQL_PPST;
+    SQLUINTEGER  value;
+    SQLLEN length_or_indicator;
+    auto ret = SQLGetData(m_handle, 1, SQL_C_ULONG, &value, sizeof(value), &length_or_indicator);
+    THROW_RET_GET(ret);
+    return value;
+}
+
+uint32 ylib::mssql::result::get_uint32(const std::string &name)
+{
+    return get_uint32(m_field_name_index[name]);
+}
+
+int64 ylib::mssql::result::get_int64(uint32 index)
+{
+    CHECK_SQL_PPST;
+    SQLBIGINT   value;
+    SQLLEN length_or_indicator;
+    auto ret = SQLGetData(m_handle, 1, SQL_C_SBIGINT, &value, sizeof(value), &length_or_indicator);
+    THROW_RET_GET(ret);
+    return value;
+}
+
+int64 ylib::mssql::result::get_int64(const std::string &name)
+{
+    return get_int64(m_field_name_index[name]);
+}
+
+uint64 ylib::mssql::result::get_uint64(uint32 index)
+{
+    CHECK_SQL_PPST;
+    SQLUBIGINT   value;
+    SQLLEN length_or_indicator;
+    auto ret = SQLGetData(m_handle, 1, SQL_C_UBIGINT, &value, sizeof(value), &length_or_indicator);
+    THROW_RET_GET(ret);
+    return value;
+}
+
+uint64 ylib::mssql::result::get_uint64(const std::string &name)
+{
+    return get_uint64(m_field_name_index[name]);
+}
+std::string ylib::mssql::result::get_string(uint32 index)
+{
+    CHECK_SQL_PPST;
+    SQLCHAR buffer[1024]; // 初始缓冲区
+    SQLLEN str_len_or_ind;
+    // 第一次调用SQLGetData来获取所需缓冲区的大小
+    SQLRETURN ret = SQLGetData(m_handle, 1, SQL_C_CHAR, buffer, sizeof(buffer), &str_len_or_ind);
+
+    if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
+        if (str_len_or_ind == SQL_NULL_DATA) {
+            return "";
+        }
+        else if (str_len_or_ind > sizeof(buffer) - 1 || ret == SQL_SUCCESS_WITH_INFO) {
+            // 缓冲区太小,需要更大的缓冲区
+            std::string data;
+            data.resize(str_len_or_ind);  // 调整字符串大小以适应全部数据
+
+            // 重新调用SQLGetData获取完整数据
+            SQLGetData(m_handle, 1, SQL_C_CHAR, &data[0], data.size() + 1, &str_len_or_ind);
+            return data;
+        }
+        else {
+            // 缓冲区足够,数据已经被完整读取
+            std::string data((char*)buffer);
+            return data;
+        }
+    }
+    throw ylib::exception("SQLGetData failed, code: "+std::to_string(ret));
+}
+std::string ylib::mssql::result::get_string(const std::string &name)
+{
+   return get_string(m_field_name_index[name]);
+}
+
+bool ylib::mssql::result::get_boolean(uint32 index)
+{
+    CHECK_SQL_PPST;
+    SQLCHAR    value;
+    SQLLEN length_or_indicator;
+    auto ret = SQLGetData(m_handle, 1, SQL_C_BIT, &value, sizeof(value), &length_or_indicator);
+    THROW_RET_GET(ret);
+    return (bool)value;
+}
+
+bool ylib::mssql::result::get_boolean(const std::string &name)
+{
+    return get_boolean(m_field_name_index[name]);
+}
+
+double ylib::mssql::result::get_double(uint32 index)
+{
+    CHECK_SQL_PPST;
+    SQLDOUBLE value;
+    SQLLEN length_or_indicator;
+    auto ret = SQLGetData(m_handle, 1, SQL_C_DOUBLE, &value, sizeof(value), &length_or_indicator);
+    THROW_RET_GET(ret);
+    return value;
+}
+
+double ylib::mssql::result::get_double(const std::string &name)
+{
+    return get_double(m_field_name_index[name]);
+}
+
+ylib::mssql::pool::pool()
+{
+    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
+    SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
+    SQLSetEnvAttr(env, SQL_ATTR_CONNECTION_POOLING, (void*)SQL_CP_ONE_PER_HENV, 0);
+}
+ylib::mssql::pool::~pool()
+{
+    SQLFreeHandle(SQL_HANDLE_ENV, env);
+}
+#endif

+ 1 - 1
src/ymysql/src/mysql_plus.cpp → src/ysql/src/mysql.cpp

@@ -1,4 +1,4 @@
-#include "ymysql/mysql_plus.h"
+#include "ysql/mysql.h"
 #include "cppconn/driver.h"
 #include "cppconn/driver.h"
 #include "cppconn/connection.h"
 #include "cppconn/connection.h"
 #include "cppconn/statement.h"
 #include "cppconn/statement.h"

+ 539 - 539
src/yutil/src/__3d/ConvertUTF.c

@@ -1,539 +1,539 @@
-/*
- * Copyright 2001-2004 Unicode, Inc.
- * 
- * Disclaimer
- * 
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
- * 
- * Limitations on Rights to Redistribute This Code
- * 
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
- */
-
-/* ---------------------------------------------------------------------
-
-    Conversions between UTF32, UTF-16, and UTF-8. Source code file.
-    Author: Mark E. Davis, 1994.
-    Rev History: Rick McGowan, fixes & updates May 2001.
-    Sept 2001: fixed const & error conditions per
-	mods suggested by S. Parent & A. Lillich.
-    June 2002: Tim Dodd added detection and handling of incomplete
-	source sequences, enhanced error detection, added casts
-	to eliminate compiler warnings.
-    July 2003: slight mods to back out aggressive FFFE detection.
-    Jan 2004: updated switches in from-UTF8 conversions.
-    Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
-
-    See the header file "ConvertUTF.h" for complete documentation.
-
------------------------------------------------------------------------- */
-
-
-#include "simpleini/ConvertUTF.h"
-#ifdef CVTUTF_DEBUG
-#include <stdio.h>
-#endif
-
-static const int halfShift  = 10; /* used for shifting by 10 bits */
-
-static const UTF32 halfBase = 0x0010000UL;
-static const UTF32 halfMask = 0x3FFUL;
-
-#define UNI_SUR_HIGH_START  (UTF32)0xD800
-#define UNI_SUR_HIGH_END    (UTF32)0xDBFF
-#define UNI_SUR_LOW_START   (UTF32)0xDC00
-#define UNI_SUR_LOW_END     (UTF32)0xDFFF
-#define false	   0
-#define true	    1
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF32toUTF16 (
-	const UTF32** sourceStart, const UTF32* sourceEnd, 
-	UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF32* source = *sourceStart;
-    UTF16* target = *targetStart;
-    while (source < sourceEnd) {
-	UTF32 ch;
-	if (target >= targetEnd) {
-	    result = targetExhausted; break;
-	}
-	ch = *source++;
-	if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
-	    /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		if (flags == strictConversion) {
-		    --source; /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		} else {
-		    *target++ = UNI_REPLACEMENT_CHAR;
-		}
-	    } else {
-		*target++ = (UTF16)ch; /* normal case */
-	    }
-	} else if (ch > UNI_MAX_LEGAL_UTF32) {
-	    if (flags == strictConversion) {
-		result = sourceIllegal;
-	    } else {
-		*target++ = UNI_REPLACEMENT_CHAR;
-	    }
-	} else {
-	    /* target is a character in range 0xFFFF - 0x10FFFF. */
-	    if (target + 1 >= targetEnd) {
-		--source; /* Back up source pointer! */
-		result = targetExhausted; break;
-	    }
-	    ch -= halfBase;
-	    *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
-	    *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
-	}
-    }
-    *sourceStart = source;
-    *targetStart = target;
-    return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF16toUTF32 (
-	const UTF16** sourceStart, const UTF16* sourceEnd, 
-	UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF16* source = *sourceStart;
-    UTF32* target = *targetStart;
-    UTF32 ch, ch2;
-    while (source < sourceEnd) {
-	const UTF16* oldSource = source; /*  In case we have to back up because of target overflow. */
-	ch = *source++;
-	/* If we have a surrogate pair, convert to UTF32 first. */
-	if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
-	    /* If the 16 bits following the high surrogate are in the source buffer... */
-	    if (source < sourceEnd) {
-		ch2 = *source;
-		/* If it's a low surrogate, convert to UTF32. */
-		if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
-		    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
-			+ (ch2 - UNI_SUR_LOW_START) + halfBase;
-		    ++source;
-		} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
-		    --source; /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		}
-	    } else { /* We don't have the 16 bits following the high surrogate. */
-		--source; /* return to the high surrogate */
-		result = sourceExhausted;
-		break;
-	    }
-	} else if (flags == strictConversion) {
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
-		--source; /* return to the illegal value itself */
-		result = sourceIllegal;
-		break;
-	    }
-	}
-	if (target >= targetEnd) {
-	    source = oldSource; /* Back up source pointer! */
-	    result = targetExhausted; break;
-	}
-	*target++ = ch;
-    }
-    *sourceStart = source;
-    *targetStart = target;
-#ifdef CVTUTF_DEBUG
-if (result == sourceIllegal) {
-    fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
-    fflush(stderr);
-}
-#endif
-    return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Index into the table below with the first byte of a UTF-8 sequence to
- * get the number of trailing bytes that are supposed to follow it.
- * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
- * left as-is for anyone who may want to do such conversion, which was
- * allowed in earlier algorithms.
- */
-static const char trailingBytesForUTF8[256] = {
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
-};
-
-/*
- * Magic values subtracted from a buffer value during UTF8 conversion.
- * This table contains as many values as there might be trailing bytes
- * in a UTF-8 sequence.
- */
-static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 
-		     0x03C82080UL, 0xFA082080UL, 0x82082080UL };
-
-/*
- * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
- * into the first byte, depending on how many bytes follow.  There are
- * as many entries in this table as there are UTF-8 sequence types.
- * (I.e., one byte sequence, two byte... etc.). Remember that sequences
- * for *legal* UTF-8 will be 4 or fewer bytes total.
- */
-static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
-
-/* --------------------------------------------------------------------- */
-
-/* The interface converts a whole buffer to avoid function-call overhead.
- * Constants have been gathered. Loops & conditionals have been removed as
- * much as possible for efficiency, in favor of drop-through switches.
- * (See "Note A" at the bottom of the file for equivalent code.)
- * If your compiler supports it, the "isLegalUTF8" call can be turned
- * into an inline function.
- */
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF16toUTF8 (
-	const UTF16** sourceStart, const UTF16* sourceEnd, 
-	UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF16* source = *sourceStart;
-    UTF8* target = *targetStart;
-    while (source < sourceEnd) {
-	UTF32 ch;
-	unsigned short bytesToWrite = 0;
-	const UTF32 byteMask = 0xBF;
-	const UTF32 byteMark = 0x80; 
-	const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
-	ch = *source++;
-	/* If we have a surrogate pair, convert to UTF32 first. */
-	if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
-	    /* If the 16 bits following the high surrogate are in the source buffer... */
-	    if (source < sourceEnd) {
-		UTF32 ch2 = *source;
-		/* If it's a low surrogate, convert to UTF32. */
-		if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
-		    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
-			+ (ch2 - UNI_SUR_LOW_START) + halfBase;
-		    ++source;
-		} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
-		    --source; /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		}
-	    } else { /* We don't have the 16 bits following the high surrogate. */
-		--source; /* return to the high surrogate */
-		result = sourceExhausted;
-		break;
-	    }
-	} else if (flags == strictConversion) {
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
-		--source; /* return to the illegal value itself */
-		result = sourceIllegal;
-		break;
-	    }
-	}
-	/* Figure out how many bytes the result will require */
-	if (ch < (UTF32)0x80) {	     bytesToWrite = 1;
-	} else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
-	} else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
-	} else if (ch < (UTF32)0x110000) {  bytesToWrite = 4;
-	} else {			    bytesToWrite = 3;
-					    ch = UNI_REPLACEMENT_CHAR;
-	}
-
-	target += bytesToWrite;
-	if (target > targetEnd) {
-	    source = oldSource; /* Back up source pointer! */
-	    target -= bytesToWrite; result = targetExhausted; break;
-	}
-	switch (bytesToWrite) { /* note: everything falls through. */
-	    case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 1: *--target =  (UTF8)(ch | firstByteMark[bytesToWrite]);
-	}
-	target += bytesToWrite;
-    }
-    *sourceStart = source;
-    *targetStart = target;
-    return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Utility routine to tell whether a sequence of bytes is legal UTF-8.
- * This must be called with the length pre-determined by the first byte.
- * If not calling this from ConvertUTF8to*, then the length can be set by:
- *  length = trailingBytesForUTF8[*source]+1;
- * and the sequence is illegal right away if there aren't that many bytes
- * available.
- * If presented with a length > 4, this returns false.  The Unicode
- * definition of UTF-8 goes up to 4-byte sequences.
- */
-
-static Boolean isLegalUTF8(const UTF8 *source, int length) {
-    UTF8 a;
-    const UTF8 *srcptr = source+length;
-    switch (length) {
-    default: return false;
-	/* Everything else falls through when "true"... */
-    case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
-    case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
-    case 2: if ((a = (*--srcptr)) > 0xBF) return false;
-
-	switch (*source) {
-	    /* no fall-through in this inner switch */
-	    case 0xE0: if (a < 0xA0) return false; break;
-	    case 0xED: if (a > 0x9F) return false; break;
-	    case 0xF0: if (a < 0x90) return false; break;
-	    case 0xF4: if (a > 0x8F) return false; break;
-	    default:   if (a < 0x80) return false;
-	}
-
-    case 1: if (*source >= 0x80 && *source < 0xC2) return false;
-    }
-    if (*source > 0xF4) return false;
-    return true;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Exported function to return whether a UTF-8 sequence is legal or not.
- * This is not used here; it's just exported.
- */
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
-    int length = trailingBytesForUTF8[*source]+1;
-    if (source+length > sourceEnd) {
-	return false;
-    }
-    return isLegalUTF8(source, length);
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF16 (
-	const UTF8** sourceStart, const UTF8* sourceEnd, 
-	UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF8* source = *sourceStart;
-    UTF16* target = *targetStart;
-    while (source < sourceEnd) {
-	UTF32 ch = 0;
-	unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
-	if (source + extraBytesToRead >= sourceEnd) {
-	    result = sourceExhausted; break;
-	}
-	/* Do this check whether lenient or strict */
-	if (! isLegalUTF8(source, extraBytesToRead+1)) {
-	    result = sourceIllegal;
-	    break;
-	}
-	/*
-	 * The cases all fall through. See "Note A" below.
-	 */
-	switch (extraBytesToRead) {
-	    case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
-	    case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
-	    case 3: ch += *source++; ch <<= 6;
-	    case 2: ch += *source++; ch <<= 6;
-	    case 1: ch += *source++; ch <<= 6;
-	    case 0: ch += *source++;
-	}
-	ch -= offsetsFromUTF8[extraBytesToRead];
-
-	if (target >= targetEnd) {
-	    source -= (extraBytesToRead+1); /* Back up source pointer! */
-	    result = targetExhausted; break;
-	}
-	if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		if (flags == strictConversion) {
-		    source -= (extraBytesToRead+1); /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		} else {
-		    *target++ = UNI_REPLACEMENT_CHAR;
-		}
-	    } else {
-		*target++ = (UTF16)ch; /* normal case */
-	    }
-	} else if (ch > UNI_MAX_UTF16) {
-	    if (flags == strictConversion) {
-		result = sourceIllegal;
-		source -= (extraBytesToRead+1); /* return to the start */
-		break; /* Bail out; shouldn't continue */
-	    } else {
-		*target++ = UNI_REPLACEMENT_CHAR;
-	    }
-	} else {
-	    /* target is a character in range 0xFFFF - 0x10FFFF. */
-	    if (target + 1 >= targetEnd) {
-		source -= (extraBytesToRead+1); /* Back up source pointer! */
-		result = targetExhausted; break;
-	    }
-	    ch -= halfBase;
-	    *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
-	    *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
-	}
-    }
-    *sourceStart = source;
-    *targetStart = target;
-    return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF32toUTF8 (
-	const UTF32** sourceStart, const UTF32* sourceEnd, 
-	UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF32* source = *sourceStart;
-    UTF8* target = *targetStart;
-    while (source < sourceEnd) {
-	UTF32 ch;
-	unsigned short bytesToWrite = 0;
-	const UTF32 byteMask = 0xBF;
-	const UTF32 byteMark = 0x80; 
-	ch = *source++;
-	if (flags == strictConversion ) {
-	    /* UTF-16 surrogate values are illegal in UTF-32 */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		--source; /* return to the illegal value itself */
-		result = sourceIllegal;
-		break;
-	    }
-	}
-	/*
-	 * Figure out how many bytes the result will require. Turn any
-	 * illegally large UTF32 things (> Plane 17) into replacement chars.
-	 */
-	if (ch < (UTF32)0x80) {	     bytesToWrite = 1;
-	} else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
-	} else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
-	} else if (ch <= UNI_MAX_LEGAL_UTF32) {  bytesToWrite = 4;
-	} else {			    bytesToWrite = 3;
-					    ch = UNI_REPLACEMENT_CHAR;
-					    result = sourceIllegal;
-	}
-	
-	target += bytesToWrite;
-	if (target > targetEnd) {
-	    --source; /* Back up source pointer! */
-	    target -= bytesToWrite; result = targetExhausted; break;
-	}
-	switch (bytesToWrite) { /* note: everything falls through. */
-	    case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
-	    case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
-	}
-	target += bytesToWrite;
-    }
-    *sourceStart = source;
-    *targetStart = target;
-    return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF32 (
-	const UTF8** sourceStart, const UTF8* sourceEnd, 
-	UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
-    ConversionResult result = conversionOK;
-    const UTF8* source = *sourceStart;
-    UTF32* target = *targetStart;
-    while (source < sourceEnd) {
-	UTF32 ch = 0;
-	unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
-	if (source + extraBytesToRead >= sourceEnd) {
-	    result = sourceExhausted; break;
-	}
-	/* Do this check whether lenient or strict */
-	if (! isLegalUTF8(source, extraBytesToRead+1)) {
-	    result = sourceIllegal;
-	    break;
-	}
-	/*
-	 * The cases all fall through. See "Note A" below.
-	 */
-	switch (extraBytesToRead) {
-	    case 5: ch += *source++; ch <<= 6;
-	    case 4: ch += *source++; ch <<= 6;
-	    case 3: ch += *source++; ch <<= 6;
-	    case 2: ch += *source++; ch <<= 6;
-	    case 1: ch += *source++; ch <<= 6;
-	    case 0: ch += *source++;
-	}
-	ch -= offsetsFromUTF8[extraBytesToRead];
-
-	if (target >= targetEnd) {
-	    source -= (extraBytesToRead+1); /* Back up the source pointer! */
-	    result = targetExhausted; break;
-	}
-	if (ch <= UNI_MAX_LEGAL_UTF32) {
-	    /*
-	     * UTF-16 surrogate values are illegal in UTF-32, and anything
-	     * over Plane 17 (> 0x10FFFF) is illegal.
-	     */
-	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
-		if (flags == strictConversion) {
-		    source -= (extraBytesToRead+1); /* return to the illegal value itself */
-		    result = sourceIllegal;
-		    break;
-		} else {
-		    *target++ = UNI_REPLACEMENT_CHAR;
-		}
-	    } else {
-		*target++ = ch;
-	    }
-	} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
-	    result = sourceIllegal;
-	    *target++ = UNI_REPLACEMENT_CHAR;
-	}
-    }
-    *sourceStart = source;
-    *targetStart = target;
-    return result;
-}
-
-/* ---------------------------------------------------------------------
-
-    Note A.
-    The fall-through switches in UTF-8 reading code save a
-    temp variable, some decrements & conditionals.  The switches
-    are equivalent to the following loop:
-	{
-	    int tmpBytesToRead = extraBytesToRead+1;
-	    do {
-		ch += *source++;
-		--tmpBytesToRead;
-		if (tmpBytesToRead) ch <<= 6;
-	    } while (tmpBytesToRead > 0);
-	}
-    In UTF-8 writing code, the switches on "bytesToWrite" are
-    similarly unrolled loops.
-
-   --------------------------------------------------------------------- */
+///*
+// * Copyright 2001-2004 Unicode, Inc.
+// * 
+// * Disclaimer
+// * 
+// * This source code is provided as is by Unicode, Inc. No claims are
+// * made as to fitness for any particular purpose. No warranties of any
+// * kind are expressed or implied. The recipient agrees to determine
+// * applicability of information provided. If this file has been
+// * purchased on magnetic or optical media from Unicode, Inc., the
+// * sole remedy for any claim will be exchange of defective media
+// * within 90 days of receipt.
+// * 
+// * Limitations on Rights to Redistribute This Code
+// * 
+// * Unicode, Inc. hereby grants the right to freely use the information
+// * supplied in this file in the creation of products supporting the
+// * Unicode Standard, and to make copies of this file in any form
+// * for internal or external distribution as long as this notice
+// * remains attached.
+// */
+//
+///* ---------------------------------------------------------------------
+//
+//    Conversions between UTF32, UTF-16, and UTF-8. Source code file.
+//    Author: Mark E. Davis, 1994.
+//    Rev History: Rick McGowan, fixes & updates May 2001.
+//    Sept 2001: fixed const & error conditions per
+//	mods suggested by S. Parent & A. Lillich.
+//    June 2002: Tim Dodd added detection and handling of incomplete
+//	source sequences, enhanced error detection, added casts
+//	to eliminate compiler warnings.
+//    July 2003: slight mods to back out aggressive FFFE detection.
+//    Jan 2004: updated switches in from-UTF8 conversions.
+//    Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
+//
+//    See the header file "ConvertUTF.h" for complete documentation.
+//
+//------------------------------------------------------------------------ */
+//
+//
+//#include "simpleini/ConvertUTF.h"
+//#ifdef CVTUTF_DEBUG
+//#include <stdio.h>
+//#endif
+//
+//static const int halfShift  = 10; /* used for shifting by 10 bits */
+//
+//static const UTF32 halfBase = 0x0010000UL;
+//static const UTF32 halfMask = 0x3FFUL;
+//
+//#define UNI_SUR_HIGH_START  (UTF32)0xD800
+//#define UNI_SUR_HIGH_END    (UTF32)0xDBFF
+//#define UNI_SUR_LOW_START   (UTF32)0xDC00
+//#define UNI_SUR_LOW_END     (UTF32)0xDFFF
+//#define false	   0
+//#define true	    1
+//
+///* --------------------------------------------------------------------- */
+//
+//ConversionResult ConvertUTF32toUTF16 (
+//	const UTF32** sourceStart, const UTF32* sourceEnd, 
+//	UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+//    ConversionResult result = conversionOK;
+//    const UTF32* source = *sourceStart;
+//    UTF16* target = *targetStart;
+//    while (source < sourceEnd) {
+//	UTF32 ch;
+//	if (target >= targetEnd) {
+//	    result = targetExhausted; break;
+//	}
+//	ch = *source++;
+//	if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+//	    /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
+//	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+//		if (flags == strictConversion) {
+//		    --source; /* return to the illegal value itself */
+//		    result = sourceIllegal;
+//		    break;
+//		} else {
+//		    *target++ = UNI_REPLACEMENT_CHAR;
+//		}
+//	    } else {
+//		*target++ = (UTF16)ch; /* normal case */
+//	    }
+//	} else if (ch > UNI_MAX_LEGAL_UTF32) {
+//	    if (flags == strictConversion) {
+//		result = sourceIllegal;
+//	    } else {
+//		*target++ = UNI_REPLACEMENT_CHAR;
+//	    }
+//	} else {
+//	    /* target is a character in range 0xFFFF - 0x10FFFF. */
+//	    if (target + 1 >= targetEnd) {
+//		--source; /* Back up source pointer! */
+//		result = targetExhausted; break;
+//	    }
+//	    ch -= halfBase;
+//	    *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+//	    *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+//	}
+//    }
+//    *sourceStart = source;
+//    *targetStart = target;
+//    return result;
+//}
+//
+///* --------------------------------------------------------------------- */
+//
+//ConversionResult ConvertUTF16toUTF32 (
+//	const UTF16** sourceStart, const UTF16* sourceEnd, 
+//	UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+//    ConversionResult result = conversionOK;
+//    const UTF16* source = *sourceStart;
+//    UTF32* target = *targetStart;
+//    UTF32 ch, ch2;
+//    while (source < sourceEnd) {
+//	const UTF16* oldSource = source; /*  In case we have to back up because of target overflow. */
+//	ch = *source++;
+//	/* If we have a surrogate pair, convert to UTF32 first. */
+//	if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+//	    /* If the 16 bits following the high surrogate are in the source buffer... */
+//	    if (source < sourceEnd) {
+//		ch2 = *source;
+//		/* If it's a low surrogate, convert to UTF32. */
+//		if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+//		    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+//			+ (ch2 - UNI_SUR_LOW_START) + halfBase;
+//		    ++source;
+//		} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+//		    --source; /* return to the illegal value itself */
+//		    result = sourceIllegal;
+//		    break;
+//		}
+//	    } else { /* We don't have the 16 bits following the high surrogate. */
+//		--source; /* return to the high surrogate */
+//		result = sourceExhausted;
+//		break;
+//	    }
+//	} else if (flags == strictConversion) {
+//	    /* UTF-16 surrogate values are illegal in UTF-32 */
+//	    if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+//		--source; /* return to the illegal value itself */
+//		result = sourceIllegal;
+//		break;
+//	    }
+//	}
+//	if (target >= targetEnd) {
+//	    source = oldSource; /* Back up source pointer! */
+//	    result = targetExhausted; break;
+//	}
+//	*target++ = ch;
+//    }
+//    *sourceStart = source;
+//    *targetStart = target;
+//#ifdef CVTUTF_DEBUG
+//if (result == sourceIllegal) {
+//    fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
+//    fflush(stderr);
+//}
+//#endif
+//    return result;
+//}
+//
+///* --------------------------------------------------------------------- */
+//
+///*
+// * Index into the table below with the first byte of a UTF-8 sequence to
+// * get the number of trailing bytes that are supposed to follow it.
+// * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+// * left as-is for anyone who may want to do such conversion, which was
+// * allowed in earlier algorithms.
+// */
+//static const char trailingBytesForUTF8[256] = {
+//    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+//    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+//    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+//    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+//    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+//    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+//    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+//    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+//};
+//
+///*
+// * Magic values subtracted from a buffer value during UTF8 conversion.
+// * This table contains as many values as there might be trailing bytes
+// * in a UTF-8 sequence.
+// */
+//static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 
+//		     0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+//
+///*
+// * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+// * into the first byte, depending on how many bytes follow.  There are
+// * as many entries in this table as there are UTF-8 sequence types.
+// * (I.e., one byte sequence, two byte... etc.). Remember that sequences
+// * for *legal* UTF-8 will be 4 or fewer bytes total.
+// */
+//static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+//
+///* --------------------------------------------------------------------- */
+//
+///* The interface converts a whole buffer to avoid function-call overhead.
+// * Constants have been gathered. Loops & conditionals have been removed as
+// * much as possible for efficiency, in favor of drop-through switches.
+// * (See "Note A" at the bottom of the file for equivalent code.)
+// * If your compiler supports it, the "isLegalUTF8" call can be turned
+// * into an inline function.
+// */
+//
+///* --------------------------------------------------------------------- */
+//
+//ConversionResult ConvertUTF16toUTF8 (
+//	const UTF16** sourceStart, const UTF16* sourceEnd, 
+//	UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+//    ConversionResult result = conversionOK;
+//    const UTF16* source = *sourceStart;
+//    UTF8* target = *targetStart;
+//    while (source < sourceEnd) {
+//	UTF32 ch;
+//	unsigned short bytesToWrite = 0;
+//	const UTF32 byteMask = 0xBF;
+//	const UTF32 byteMark = 0x80; 
+//	const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
+//	ch = *source++;
+//	/* If we have a surrogate pair, convert to UTF32 first. */
+//	if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+//	    /* If the 16 bits following the high surrogate are in the source buffer... */
+//	    if (source < sourceEnd) {
+//		UTF32 ch2 = *source;
+//		/* If it's a low surrogate, convert to UTF32. */
+//		if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+//		    ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+//			+ (ch2 - UNI_SUR_LOW_START) + halfBase;
+//		    ++source;
+//		} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+//		    --source; /* return to the illegal value itself */
+//		    result = sourceIllegal;
+//		    break;
+//		}
+//	    } else { /* We don't have the 16 bits following the high surrogate. */
+//		--source; /* return to the high surrogate */
+//		result = sourceExhausted;
+//		break;
+//	    }
+//	} else if (flags == strictConversion) {
+//	    /* UTF-16 surrogate values are illegal in UTF-32 */
+//	    if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+//		--source; /* return to the illegal value itself */
+//		result = sourceIllegal;
+//		break;
+//	    }
+//	}
+//	/* Figure out how many bytes the result will require */
+//	if (ch < (UTF32)0x80) {	     bytesToWrite = 1;
+//	} else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
+//	} else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
+//	} else if (ch < (UTF32)0x110000) {  bytesToWrite = 4;
+//	} else {			    bytesToWrite = 3;
+//					    ch = UNI_REPLACEMENT_CHAR;
+//	}
+//
+//	target += bytesToWrite;
+//	if (target > targetEnd) {
+//	    source = oldSource; /* Back up source pointer! */
+//	    target -= bytesToWrite; result = targetExhausted; break;
+//	}
+//	switch (bytesToWrite) { /* note: everything falls through. */
+//	    case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+//	    case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+//	    case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+//	    case 1: *--target =  (UTF8)(ch | firstByteMark[bytesToWrite]);
+//	}
+//	target += bytesToWrite;
+//    }
+//    *sourceStart = source;
+//    *targetStart = target;
+//    return result;
+//}
+//
+///* --------------------------------------------------------------------- */
+//
+///*
+// * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+// * This must be called with the length pre-determined by the first byte.
+// * If not calling this from ConvertUTF8to*, then the length can be set by:
+// *  length = trailingBytesForUTF8[*source]+1;
+// * and the sequence is illegal right away if there aren't that many bytes
+// * available.
+// * If presented with a length > 4, this returns false.  The Unicode
+// * definition of UTF-8 goes up to 4-byte sequences.
+// */
+//
+//static Boolean isLegalUTF8(const UTF8 *source, int length) {
+//    UTF8 a;
+//    const UTF8 *srcptr = source+length;
+//    switch (length) {
+//    default: return false;
+//	/* Everything else falls through when "true"... */
+//    case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+//    case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
+//    case 2: if ((a = (*--srcptr)) > 0xBF) return false;
+//
+//	switch (*source) {
+//	    /* no fall-through in this inner switch */
+//	    case 0xE0: if (a < 0xA0) return false; break;
+//	    case 0xED: if (a > 0x9F) return false; break;
+//	    case 0xF0: if (a < 0x90) return false; break;
+//	    case 0xF4: if (a > 0x8F) return false; break;
+//	    default:   if (a < 0x80) return false;
+//	}
+//
+//    case 1: if (*source >= 0x80 && *source < 0xC2) return false;
+//    }
+//    if (*source > 0xF4) return false;
+//    return true;
+//}
+//
+///* --------------------------------------------------------------------- */
+//
+///*
+// * Exported function to return whether a UTF-8 sequence is legal or not.
+// * This is not used here; it's just exported.
+// */
+//Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
+//    int length = trailingBytesForUTF8[*source]+1;
+//    if (source+length > sourceEnd) {
+//	return false;
+//    }
+//    return isLegalUTF8(source, length);
+//}
+//
+///* --------------------------------------------------------------------- */
+//
+//ConversionResult ConvertUTF8toUTF16 (
+//	const UTF8** sourceStart, const UTF8* sourceEnd, 
+//	UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
+//    ConversionResult result = conversionOK;
+//    const UTF8* source = *sourceStart;
+//    UTF16* target = *targetStart;
+//    while (source < sourceEnd) {
+//	UTF32 ch = 0;
+//	unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+//	if (source + extraBytesToRead >= sourceEnd) {
+//	    result = sourceExhausted; break;
+//	}
+//	/* Do this check whether lenient or strict */
+//	if (! isLegalUTF8(source, extraBytesToRead+1)) {
+//	    result = sourceIllegal;
+//	    break;
+//	}
+//	/*
+//	 * The cases all fall through. See "Note A" below.
+//	 */
+//	switch (extraBytesToRead) {
+//	    case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+//	    case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
+//	    case 3: ch += *source++; ch <<= 6;
+//	    case 2: ch += *source++; ch <<= 6;
+//	    case 1: ch += *source++; ch <<= 6;
+//	    case 0: ch += *source++;
+//	}
+//	ch -= offsetsFromUTF8[extraBytesToRead];
+//
+//	if (target >= targetEnd) {
+//	    source -= (extraBytesToRead+1); /* Back up source pointer! */
+//	    result = targetExhausted; break;
+//	}
+//	if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+//	    /* UTF-16 surrogate values are illegal in UTF-32 */
+//	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+//		if (flags == strictConversion) {
+//		    source -= (extraBytesToRead+1); /* return to the illegal value itself */
+//		    result = sourceIllegal;
+//		    break;
+//		} else {
+//		    *target++ = UNI_REPLACEMENT_CHAR;
+//		}
+//	    } else {
+//		*target++ = (UTF16)ch; /* normal case */
+//	    }
+//	} else if (ch > UNI_MAX_UTF16) {
+//	    if (flags == strictConversion) {
+//		result = sourceIllegal;
+//		source -= (extraBytesToRead+1); /* return to the start */
+//		break; /* Bail out; shouldn't continue */
+//	    } else {
+//		*target++ = UNI_REPLACEMENT_CHAR;
+//	    }
+//	} else {
+//	    /* target is a character in range 0xFFFF - 0x10FFFF. */
+//	    if (target + 1 >= targetEnd) {
+//		source -= (extraBytesToRead+1); /* Back up source pointer! */
+//		result = targetExhausted; break;
+//	    }
+//	    ch -= halfBase;
+//	    *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+//	    *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+//	}
+//    }
+//    *sourceStart = source;
+//    *targetStart = target;
+//    return result;
+//}
+//
+///* --------------------------------------------------------------------- */
+//
+//ConversionResult ConvertUTF32toUTF8 (
+//	const UTF32** sourceStart, const UTF32* sourceEnd, 
+//	UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
+//    ConversionResult result = conversionOK;
+//    const UTF32* source = *sourceStart;
+//    UTF8* target = *targetStart;
+//    while (source < sourceEnd) {
+//	UTF32 ch;
+//	unsigned short bytesToWrite = 0;
+//	const UTF32 byteMask = 0xBF;
+//	const UTF32 byteMark = 0x80; 
+//	ch = *source++;
+//	if (flags == strictConversion ) {
+//	    /* UTF-16 surrogate values are illegal in UTF-32 */
+//	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+//		--source; /* return to the illegal value itself */
+//		result = sourceIllegal;
+//		break;
+//	    }
+//	}
+//	/*
+//	 * Figure out how many bytes the result will require. Turn any
+//	 * illegally large UTF32 things (> Plane 17) into replacement chars.
+//	 */
+//	if (ch < (UTF32)0x80) {	     bytesToWrite = 1;
+//	} else if (ch < (UTF32)0x800) {     bytesToWrite = 2;
+//	} else if (ch < (UTF32)0x10000) {   bytesToWrite = 3;
+//	} else if (ch <= UNI_MAX_LEGAL_UTF32) {  bytesToWrite = 4;
+//	} else {			    bytesToWrite = 3;
+//					    ch = UNI_REPLACEMENT_CHAR;
+//					    result = sourceIllegal;
+//	}
+//	
+//	target += bytesToWrite;
+//	if (target > targetEnd) {
+//	    --source; /* Back up source pointer! */
+//	    target -= bytesToWrite; result = targetExhausted; break;
+//	}
+//	switch (bytesToWrite) { /* note: everything falls through. */
+//	    case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+//	    case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+//	    case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+//	    case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
+//	}
+//	target += bytesToWrite;
+//    }
+//    *sourceStart = source;
+//    *targetStart = target;
+//    return result;
+//}
+//
+///* --------------------------------------------------------------------- */
+//
+//ConversionResult ConvertUTF8toUTF32 (
+//	const UTF8** sourceStart, const UTF8* sourceEnd, 
+//	UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
+//    ConversionResult result = conversionOK;
+//    const UTF8* source = *sourceStart;
+//    UTF32* target = *targetStart;
+//    while (source < sourceEnd) {
+//	UTF32 ch = 0;
+//	unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+//	if (source + extraBytesToRead >= sourceEnd) {
+//	    result = sourceExhausted; break;
+//	}
+//	/* Do this check whether lenient or strict */
+//	if (! isLegalUTF8(source, extraBytesToRead+1)) {
+//	    result = sourceIllegal;
+//	    break;
+//	}
+//	/*
+//	 * The cases all fall through. See "Note A" below.
+//	 */
+//	switch (extraBytesToRead) {
+//	    case 5: ch += *source++; ch <<= 6;
+//	    case 4: ch += *source++; ch <<= 6;
+//	    case 3: ch += *source++; ch <<= 6;
+//	    case 2: ch += *source++; ch <<= 6;
+//	    case 1: ch += *source++; ch <<= 6;
+//	    case 0: ch += *source++;
+//	}
+//	ch -= offsetsFromUTF8[extraBytesToRead];
+//
+//	if (target >= targetEnd) {
+//	    source -= (extraBytesToRead+1); /* Back up the source pointer! */
+//	    result = targetExhausted; break;
+//	}
+//	if (ch <= UNI_MAX_LEGAL_UTF32) {
+//	    /*
+//	     * UTF-16 surrogate values are illegal in UTF-32, and anything
+//	     * over Plane 17 (> 0x10FFFF) is illegal.
+//	     */
+//	    if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+//		if (flags == strictConversion) {
+//		    source -= (extraBytesToRead+1); /* return to the illegal value itself */
+//		    result = sourceIllegal;
+//		    break;
+//		} else {
+//		    *target++ = UNI_REPLACEMENT_CHAR;
+//		}
+//	    } else {
+//		*target++ = ch;
+//	    }
+//	} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+//	    result = sourceIllegal;
+//	    *target++ = UNI_REPLACEMENT_CHAR;
+//	}
+//    }
+//    *sourceStart = source;
+//    *targetStart = target;
+//    return result;
+//}
+//
+///* ---------------------------------------------------------------------
+//
+//    Note A.
+//    The fall-through switches in UTF-8 reading code save a
+//    temp variable, some decrements & conditionals.  The switches
+//    are equivalent to the following loop:
+//	{
+//	    int tmpBytesToRead = extraBytesToRead+1;
+//	    do {
+//		ch += *source++;
+//		--tmpBytesToRead;
+//		if (tmpBytesToRead) ch <<= 6;
+//	    } while (tmpBytesToRead > 0);
+//	}
+//    In UTF-8 writing code, the switches on "bytesToWrite" are
+//    similarly unrolled loops.
+//
+//   --------------------------------------------------------------------- */

+ 5 - 0
src/yutil/src/debug.cpp

@@ -87,4 +87,9 @@ void ylib::debug::detect_exception()
 {
 {
     SetUnhandledExceptionFilter(ExceptionFilter);
     SetUnhandledExceptionFilter(ExceptionFilter);
 }
 }
+void ylib::debug::vs_console_println(const std::string& value)
+{
+    std::string v2 = value + "\n";
+    OutputDebugString(value.c_str());
+}
 #endif
 #endif