1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Utility/BsPlatformUtility.h"
4#include <stdlib.h>
5#include <uuid/uuid.h>
6#include <sys/utsname.h>
7
8#include <unicode/ustring.h>
9#include <unicode/utypes.h>
10#include <unicode/udata.h>
11#include <unicode/uversion.h>
12
13namespace bs
14{
15 /** Define a stub 'entry-point' required by ICU. **/
16 typedef struct
17 {
18 uint16_t headerSize;
19 uint8_t magic1, magic2;
20 UDataInfo info;
21 char padding[8];
22 uint32_t count, reserved;
23 int fakeNameAndData[4];
24 } ICU_Data_Header;
25
26 extern "C" U_EXPORT const ICU_Data_Header U_ICUDATA_ENTRY_POINT = {
27 32, /* headerSize */
28 0xda, /* magic1, (see struct MappedData in udata.c) */
29 0x27, /* magic2 */
30 { /*UDataInfo */
31 sizeof(UDataInfo), /* size */
32 0, /* reserved */
33
34 #if U_IS_BIG_ENDIAN
35 1,
36 #else
37 0,
38 #endif
39
40 U_CHARSET_FAMILY,
41 sizeof(UChar),
42 0, /* reserved */
43 { /* data format identifier */
44 0x54, 0x6f, 0x43, 0x50}, /* "ToCP" */
45 {1, 0, 0, 0}, /* format version major, minor, milli, micro */
46 {0, 0, 0, 0} /* dataVersion */
47 },
48 {0, 0, 0, 0, 0, 0, 0, 0}, /* Padding[8] */
49 0, /* count */
50 0, /* Reserved */
51 { /* TOC structure */
52/* { */
53 0, 0, 0, 0 /* name and data entries. Count says there are none, */
54 /* but put one in just in case. */
55/* } */
56 }
57 };
58
59 GPUInfo PlatformUtility::sGPUInfo;
60
61 void PlatformUtility::terminate(bool force)
62 {
63 // TODOPORT - Support clean exit by sending the main window a quit message
64 exit(0);
65 }
66
67 SystemInfo PlatformUtility::getSystemInfo()
68 {
69 SystemInfo output;
70
71 // Get CPU vendor, model and number of cores
72 {
73 std::ifstream file("/proc/cpuinfo");
74 std::string line;
75 while(std::getline(file, line))
76 {
77 std::stringstream lineStream(line);
78 std::string token;
79 lineStream >> token;
80
81 if(token == "vendor_id")
82 {
83 if(lineStream >> token && token == ":")
84 {
85 std::string vendorId;
86 if(lineStream >> vendorId)
87 output.cpuManufacturer = vendorId.c_str();
88 }
89 }
90 else if(token == "model")
91 {
92 if(lineStream >> token && token == "name")
93 {
94 if (lineStream >> token && token == ":")
95 {
96 std::stringstream modelName;
97 if (lineStream >> token)
98 {
99 modelName << token;
100
101 while (lineStream >> token)
102 modelName << " " << token;
103 }
104
105 output.cpuModel = modelName.str().c_str();
106 }
107 }
108 }
109 else if(token == "cpu")
110 {
111 if(lineStream >> token)
112 {
113 if (token == "cores")
114 {
115 if (lineStream >> token && token == ":")
116 {
117 UINT32 numCores;
118 if (lineStream >> numCores)
119 output.cpuNumCores = numCores;
120 }
121 }
122 }
123 }
124 }
125 }
126
127 // Get CPU frequency
128 {
129 std::ifstream file("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
130 UINT32 frequency;
131 if(file >> frequency)
132 output.cpuClockSpeedMhz = frequency / 1000;
133 }
134
135 // Get amount of system memory
136 {
137 std::ifstream file("/proc/meminfo");
138 std::string token;
139 while(file >> token)
140 {
141 if(token == "MemTotal:")
142 {
143 UINT32 memTotal;
144 if(file >> memTotal)
145 output.memoryAmountMb = memTotal / 1024;
146 else
147 output.memoryAmountMb = 0;
148
149 break;
150 }
151
152 // Ignore the rest of the line
153 file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
154 }
155 }
156
157 // Get OS version
158 utsname osInfo;
159 uname(&osInfo);
160
161 // Note: This won't report the exact distro
162 output.osName = String(osInfo.sysname) + String(osInfo.version);
163
164 if (BS_ARCH_TYPE == BS_ARCHITECTURE_x86_64)
165 output.osIs64Bit = true;
166 else
167 output.osIs64Bit = strstr(osInfo.machine, "64") != nullptr;
168
169 // Get GPU info
170 output.gpuInfo = sGPUInfo;
171
172 return output;
173 }
174
175 String PlatformUtility::convertCaseUTF8(const String& input, bool toUpper)
176 {
177 UErrorCode errorCode = U_ZERO_ERROR;
178
179 auto inputLen = (int32_t)input.size();
180 int32_t bufferLen = 0;
181 u_strFromUTF8(nullptr, 0, &bufferLen, input.data(), inputLen, &errorCode);
182
183 auto uStr = bs_stack_alloc<UChar>((UINT32)bufferLen);
184 int32_t uStrLen = 0;
185 errorCode = U_ZERO_ERROR;
186 u_strFromUTF8(uStr, bufferLen * sizeof(UChar), &uStrLen, input.data(), inputLen, &errorCode);
187
188 errorCode = U_ZERO_ERROR;
189 if(toUpper)
190 bufferLen = u_strToUpper(nullptr, 0, uStr, uStrLen, nullptr, &errorCode);
191 else
192 bufferLen = u_strToLower(nullptr, 0, uStr, uStrLen, nullptr, &errorCode);
193
194 auto convertedUStr = bs_stack_alloc<UChar>((UINT32) bufferLen);
195 int32_t convertedUStrLen = 0;
196
197 errorCode = U_ZERO_ERROR;
198 if(toUpper)
199 convertedUStrLen = u_strToUpper(convertedUStr, bufferLen * sizeof(UChar), uStr, uStrLen, nullptr, &errorCode);
200 else
201 convertedUStrLen = u_strToLower(convertedUStr, bufferLen * sizeof(UChar), uStr, uStrLen, nullptr, &errorCode);
202
203 errorCode = U_ZERO_ERROR;
204 u_strToUTF8(nullptr, 0, &bufferLen, convertedUStr, convertedUStrLen, &errorCode);
205
206 int32_t outputStrLen = 0;
207 auto outputStr = bs_stack_alloc<char>(bufferLen);
208
209 errorCode = U_ZERO_ERROR;
210 u_strToUTF8(outputStr, bufferLen, &outputStrLen, convertedUStr, convertedUStrLen, &errorCode);
211
212 String output(outputStr, outputStrLen);
213
214 bs_stack_free(outputStr);
215 bs_stack_free(convertedUStr);
216 bs_stack_free(uStr);
217
218 return output;
219 }
220
221 UUID PlatformUtility::generateUUID()
222 {
223 uuid_t nativeUUID;
224 uuid_generate(nativeUUID);
225
226 return UUID(
227 *(UINT32*)&nativeUUID[0],
228 *(UINT32*)&nativeUUID[4],
229 *(UINT32*)&nativeUUID[8],
230 *(UINT32*)&nativeUUID[12]);
231 }
232}
233