-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwincompat.h
135 lines (125 loc) · 3.72 KB
/
wincompat.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#ifndef OBJMASTER_WIN_COMPAT
#define OBJMASTER_WIN_COMPAT
// This file is intended to add various clever or dirty tricks to achieve windows MSVC compatibility...
// Only do these things if the compiler is M$C...
#ifdef _MSC_VER
#include <vector>
#include <string>
#include <stdexcept>
// Silly hax for getting rid of errors arising from missing proper posix method names on windows MSVC...
#define strdup _strdup
// strtop_r is not present in MSVC, but there is this random method that basically do the same...
#define strtok_r strtok_s
// strncpy seems to be unsafe in microsoft opinions so we need to hack around this a bit
#define strncpy windows_hacky_strncpy
static char *windows_hacky_strncpy(char *dest, const char *src, size_t n) {
// I think this is only "more safe" when chars are not 8 bit represented...
strncpy_s(dest, n * sizeof(char), src, n);
return dest;
}
/** Various helper functions for UTF-8 and UTF-16 (mostly only needed on windows) */
class UtfHelper {
public:
/** Converts an utf8 string to utf16 - one could use codecvt but many platforms deprecate it completely or plain miss implementation for that */
// Rem.: Please do not use wstring at all when on "proper" operating systems - like *nix, *bsd, android, emscripten/webgl etc...
static inline std::wstring utf8_to_utf16(const std::string& utf8)
{
std::vector<unsigned long> unicode;
size_t i = 0;
while (i < utf8.size())
{
unsigned long uni;
size_t todo;
bool error = false;
unsigned char ch = utf8[i++];
if (ch <= 0x7F)
{
uni = ch;
todo = 0;
}
else if (ch <= 0xBF)
{
throw std::logic_error("not a UTF-8 string");
}
else if (ch <= 0xDF)
{
uni = ch & 0x1F;
todo = 1;
}
else if (ch <= 0xEF)
{
uni = ch & 0x0F;
todo = 2;
}
else if (ch <= 0xF7)
{
uni = ch & 0x07;
todo = 3;
}
else
{
throw std::logic_error("not a UTF-8 string");
}
for (size_t j = 0; j < todo; ++j)
{
if (i == utf8.size())
throw std::logic_error("not a UTF-8 string");
unsigned char ch = utf8[i++];
if (ch < 0x80 || ch > 0xBF)
throw std::logic_error("not a UTF-8 string");
uni <<= 6;
uni += ch & 0x3F;
}
if (uni >= 0xD800 && uni <= 0xDFFF) {
// FIXME: Windows enables path names with these although they are not standard. What to do? I choose not to implement them...
throw std::logic_error("not a UTF-8 string");
}
if (uni > 0x10FFFF)
throw std::logic_error("not a UTF-8 string");
unicode.push_back(uni);
}
std::wstring utf16;
/*
// DEBUG: print out the unicode code-space values
fprintf(stderr, "UNICODE: ");
for (size_t i = 0; i < unicode.size(); ++i)
{
fprintf(stderr, "%lx ", unicode[i]);
}
fprintf(stderr, "\n");
*/
for (size_t i = 0; i < unicode.size(); ++i)
{
unsigned long uni = unicode[i];
if (uni <= 0xFFFF)
{
utf16 += (wchar_t)uni;
}
else
{
// Support for the whole code-space is here (bigger than 16 bit values)
uni -= 0x10000;
// Unicode is a 20 bits wide code-space
// When we need more than 16 bits
// we first take the upper 10 bits and add that to 0xD800 => first char
auto upper = (wchar_t)((uni >> 10) + 0xD800);
// Then we take the lower 10 bits by and-ing with 0x3FF and add 0xDC00 => second char
auto lower = (wchar_t)((uni & 0x3FF) + 0xDC00);
utf16 += upper;
utf16 += lower;
// See: https://en.wikipedia.org/wiki/UTF-16#U+D800_to_U+DFFF
/* // Test for \u1313F bird sign - they both pass!
if (upper == 0xD80C) {
fprintf(stderr, "UPPER GOOD\n");
} else fprintf(stderr, "UPPER BAD\n");
if (lower == 0xDD3F) {
fprintf(stderr, "LOWER GOOD\n");
} else fprintf(stderr, "LOWER BAD\n");
*/
}
}
return utf16;
}
};
#endif
#endif