Merge pull request #2512 from spnethw/tmppanel_fix_menu_from_file_list_crash
[far2l.git] / utils / src / WideMB.cpp
blob79c0686600361a3657e12646eb9db4b4c136d726
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <string.h>
4 #include <vector>
5 #include "utils.h"
6 #include "UtfConvert.hpp"
8 //NB: Routines here should not affect errno
10 //////////////////////////////////////////////////////
12 static size_t MB2Wide_Internal(const char *src_begin, size_t &src_len, std::wstring &dst, bool append)
14 if (!append) {
15 dst.clear();
17 if (!src_len) {
18 return std::string::npos;
21 auto src = src_begin;
22 auto src_end = src_begin + src_len;
23 auto src_incomplete_tail = src_end;
24 size_t dst_incomplete_tail_pos = (size_t)-1;
26 struct EscapedStringPushBack : public StdPushBack<std::wstring>
28 EscapedStringPushBack(std::wstring &dst) : StdPushBack<std::wstring>(dst) {}
30 inline void push_back(const value_type &v)
32 StdPushBack<std::wstring>::push_back(v);
33 if (UNLIKELY(v == WCHAR_ESCAPING)) {
34 StdPushBack<std::wstring>::push_back(WCHAR_ESCAPING);
38 } pb(dst);
40 for (;;) {
41 size_t src_piece = src_end - src;
42 const unsigned ucr = UtfConvert(src, src_piece, pb, true);
43 src+= src_piece;
44 if (ucr == 0) {
45 break;
48 if (dst_incomplete_tail_pos == (size_t)-1 && src != src_end
49 && src_end - src < MAX_MB_CHARS_PER_WCHAR) {
50 dst_incomplete_tail_pos = dst.size();
51 src_incomplete_tail = src;
54 const auto remain = src_end - src;
55 if (remain != 0) {
56 const unsigned char uc = (unsigned char)*src;
57 dst.push_back(WCHAR_ESCAPING);
58 dst.push_back((wchar_t)MakeHexDigit(uc >> 4));
59 dst.push_back((wchar_t)MakeHexDigit(uc & 0xf));
61 // fprintf(stderr, "CE: @%lu %x\n", src - src_begin, ucr);
63 if (remain <= 1) {
64 if (dst_incomplete_tail_pos != (size_t)-1) {
65 src_len = src_incomplete_tail - src_begin;
66 return dst_incomplete_tail_pos;
68 src_len = src - src_begin;
69 break;
71 ++src;
74 return dst.size();
77 size_t MB2Wide_HonorIncomplete(const char *src, size_t src_len, std::wstring &dst, bool append)
79 size_t dst_incomplete_tail_pos = MB2Wide_Internal(src, src_len, dst, append);
80 if (dst_incomplete_tail_pos != std::string::npos) {
81 dst.resize(dst_incomplete_tail_pos);
83 return src_len;
86 unsigned MB2Wide_Unescaped(const char *src_begin, size_t &src_len, wchar_t &dst, bool fail_on_illformed)
88 ArrayPushBack<wchar_t> pb(&dst, (&dst) + 1);
89 unsigned out = UtfConvert(src_begin, src_len, pb, fail_on_illformed);
90 out&= ~CONV_NEED_MORE_DST;
91 return out;
94 unsigned MB2Wide_Unescaped(const char *src, size_t &src_len, wchar_t *dst, size_t &dst_len, bool fail_on_illformed)
96 ArrayPushBack<wchar_t> pb(dst, dst + dst_len);
97 unsigned out = UtfConvert(src, src_len, pb, fail_on_illformed);
98 dst_len = pb.size();
99 return out;
102 unsigned int Wide2MB_Unescaped(const wchar_t *src, size_t &src_len, char *dst, size_t &dst_len, bool fail_on_illformed)
104 ArrayPushBack<char> pb(dst, dst + dst_len);
105 unsigned out = UtfConvert(src, src_len, pb, fail_on_illformed);
106 dst_len = pb.size();
107 return out;
110 void MB2Wide(const char *src, size_t src_len, std::wstring &dst, bool append)
112 MB2Wide_Internal(src, src_len, dst, append);
115 //////////////////
117 void Wide2MB_UnescapedAppend(const wchar_t wc, std::string &dst)
119 size_t len = 1;
120 StdPushBack<std::string> pb(dst);
121 UtfConvert(&wc, len, pb, false);
124 void Wide2MB_UnescapedAppend(const wchar_t *src_begin, size_t src_len, std::string &dst)
126 StdPushBack<std::string> pb(dst);
127 UtfConvert(src_begin, src_len, pb, false);
130 static inline bool IsLowCaseHexDigit(const wchar_t c)
132 return (c >= L'0' && c <= L'9') || (c >= L'a' && c <= L'f');
135 void Wide2MB(const wchar_t *src_begin, size_t src_len, std::string &dst, bool append)
137 if (!append) {
138 dst.clear();
140 if (!src_len) {
141 return;
144 auto src = src_begin, src_end = src_begin + src_len;
146 while (src != src_end) {
147 if (LIKELY(src[0] != WCHAR_ESCAPING)) {
148 ++src;
150 } else {
151 if (src_begin != src) {
152 Wide2MB_UnescapedAppend(src_begin, src - src_begin, dst);
154 if (LIKELY(src_end - src >= 3 && IsLowCaseHexDigit(src[1]) && IsLowCaseHexDigit(src[2]))) {
155 dst+= ParseHexByte(&src[1]);
156 src+= 3;
158 } else {
159 Wide2MB_UnescapedAppend(src, 1, dst);
160 ++src;
161 if (src_end != src && *src == WCHAR_ESCAPING) {
162 ++src;
165 src_begin = src;
169 if (src_begin != src) {
170 Wide2MB_UnescapedAppend(src_begin, src - src_begin, dst);
174 //////////////////
176 void Wide2MB(const wchar_t *src, std::string &dst, bool append)
178 Wide2MB(src, wcslen(src), dst, append);
181 void MB2Wide(const char *src, std::wstring &dst, bool append)
183 MB2Wide(src, strlen(src), dst, append);
186 std::string Wide2MB(const wchar_t *src)
188 std::string dst;
189 Wide2MB(src, dst, true);
190 return dst;
193 std::wstring MB2Wide(const char *src)
195 std::wstring dst;
196 MB2Wide(src, dst, true);
197 return dst;
200 void StrWide2MB(const std::wstring &src, std::string &dst, bool append)
202 Wide2MB(src.c_str(), src.size(), dst, append);
205 std::string StrWide2MB(const std::wstring &src)
207 std::string dst;
208 Wide2MB(src.c_str(), src.size(), dst, true);
209 return dst;
212 void StrMB2Wide(const std::string &src, std::wstring &dst, bool append)
214 MB2Wide(src.c_str(), src.size(), dst, append);
217 std::wstring StrMB2Wide(const std::string &src)
219 std::wstring dst;
220 MB2Wide(src.c_str(), src.size(), dst, true);
221 return dst;