1 module appbase.utils.utility;
2 
3 import std.file;
4 import std.path;
5 import std..string;
6 import std.conv;
7 import std.datetime;
8 import std.array;
9 import std.uuid : randomUUID;
10 import std.random;
11 import std.digest : toHexString;
12 import std.digest.md : MD5Digest;
13 import std.digest.ripemd : RIPEMD160Digest;
14 import std.regex;
15 import std.algorithm;
16 import std.traits : Unqual;
17 import std.zlib;
18 
19 string getExePath()
20 {
21     return dirName(thisExePath);
22 }
23 
24 string getExeName()
25 {
26     return baseName(thisExePath);
27 }
28 
29 string genUuid(const bool hasSeparator = false)
30 {
31     string str = randomUUID.toString;
32     return hasSeparator ? str : str.replace("-", "").toUpper();
33 }
34 
35 string randomAlphanumeric(const size_t length)
36 {
37     if (length <= 0)
38     {
39         return string.init;
40     }
41 
42     immutable char[] chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
43     char[] result = new char[length];
44 
45     for (size_t i = 0; i < length; i++)
46     {
47         result[i] = chars[rnd.next!byte(1, chars.length) - 1];
48     }
49 
50     return cast(immutable char[])result;
51 }
52 
53 string MD5(scope const(void[])[] src...)
54 {
55     auto md5 = new MD5Digest();
56     ubyte[] hash = md5.digest(src);
57 
58     return hash.toHexString!(LetterCase.upper);
59 }
60 
61 string RIPEMD160(scope const(void[])[] src...)
62 {
63     auto md = new RIPEMD160Digest();
64     ubyte[] hash = md.digest(src);
65 
66     return hash.toHexString!(LetterCase.upper);
67 }
68 
69 string Hash(int bits)(scope const(void[])[] src...)
70 if (bits == 128 || bits == 160)
71 {
72     static if (bits == 128)
73         return MD5(src);
74     else
75         return RIPEMD160(src);
76 }
77 
78 ubyte[] strToByte_hex(string input)
79 {
80     if (input == string.init)
81     {
82         return null;
83     }
84 
85     Appender!(ubyte[]) app;
86 
87     for (size_t i; i < input.length; i += 2)
88     {
89         app.put(input[i .. i + 2].to!ubyte(16));
90     }
91 
92     return app.data;
93 }
94 
95 string byteToStr_hex(T = ubyte)(T[] buffer)
96 {
97     if (buffer.length == 0)
98     {
99         return string.init;
100     }
101 
102     Appender!string app;
103 
104     foreach (b; buffer)
105     {
106         app.put(rightJustify(b.to!string(16).toUpper(), 2, '0'));
107     }
108 
109     return app.data;
110 }
111 
112 bool isIPAddress(string ip)
113 {
114     auto re = regex(`^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$`);
115     return !match(ip, re).empty();
116 }
117 
118 long ipToLong(string ip)
119 {
120     auto part = split(ip, ".");
121 
122     if (part.length != 4)
123     {
124         return 0;
125     }
126 
127     long r = as!long(part[3], 0);
128 
129     for (int i = 2; i >= 0; i--)
130     {
131         r += as!long(part[i], 0) << 8 * (3 - i);
132     }
133 
134     return r;
135 }
136 
137 string ipFromLong(long ipInt)
138 {
139     string[4] part;
140 
141     for (int i = 3; i >= 0; i--)
142     {
143         part[i] = to!string(ipInt % 256);
144         ipInt /= 256;
145     }
146 
147     return mergeString(
148         part[0].to!string, ".",
149         part[1].to!string, ".",
150         part[2].to!string, ".",
151         part[3].to!string
152     );
153 }
154 
155 string mergeString(Params...)(Params params)
156 {
157     Appender!string ret;
158 
159     foreach(str; params)
160     {
161         ret.put(str);
162     }
163 
164     return ret.data;
165 }
166 
167 T as(T = int)(string src, T defaultValue = T.init)
168 {
169     try
170     {
171         return to!T(src);
172     }
173     catch (Exception e)
174     {
175         return defaultValue;
176     }
177 }
178 
179 string floatAsString(T = double)(T value) if (is(Unqual!T == double) || is(Unqual!T == float) || is(Unqual!T == real))
180 {
181     long l = cast(long)value;
182     T f = value - l;
183 
184     return to!string(l) ~ ((f > 0) ? f.to!string[1 .. $] : "");
185 }
186 
187 string dateTimeToString(DateTime dt)    // 2017-12-01 00:01:01
188 {
189     return dt.date().toISOExtString() ~ " " ~ dt.timeOfDay().toISOExtString();
190 }
191 
192 DateTime dateTimeFromString(string dt, DateTime defaultValue = DateTime.init)
193 {
194     if ((dt.length > 10) && (dt[10] == ' '))
195     {
196         dt = dt.replace(" ", "T");
197     }
198 
199     try
200     {
201         return DateTime.fromISOExtString(dt);
202     }
203     catch (Exception e)
204     {
205         return defaultValue;
206     }
207 }
208 
209 SysTime sysTimeFromString(string dt, SysTime defaultValue = SysTime.init)
210 {
211     dt = strip(dt);
212 
213     if ((dt.length > 10) && (dt[10] == 32))
214     {
215         dt = dt.replace("\x20", "T");
216     }
217 
218     try
219     {
220         return SysTime.fromISOExtString(dt);
221     }
222     catch (Exception e)
223     {
224         return defaultValue;
225     }
226 }
227 
228 DateTime now()
229 {
230     return cast(DateTime)Clock.currTime;
231 }
232 
233 private const long TICK_BASE = 1460004240;
234 
235 long currTimeTick()
236 {
237     return Clock.currTime().toUnixTime() - TICK_BASE;
238 }
239 
240 SysTime currTimeFromTick(long tick)
241 {
242     return SysTime.fromUnixTime(tick + TICK_BASE);
243 }
244 
245 bool inArray(T)(in T[] _array, in T v)
246 {
247     return _array.any!(x => x == v);
248 }
249 
250 bool inArray(T)(in T[] _array, in T[] _sub_array)
251 {
252     foreach (v; _sub_array)
253     {
254         if (!inArray!T(_array, v))
255         {
256             return false;
257         }
258     }
259 
260     return true;
261 }
262 
263 bool inArray(T)(in T[][] _array, in T[] _sub_array)
264 {
265     foreach (v; _array)
266     {
267         if (v == _sub_array)
268         {
269             return true;
270         }
271     }
272 
273     return false;
274 }
275 
276 bool hasCross(T)(in T[] _array, in T[] arr)
277 {
278     foreach (v; arr)
279     {
280         if (inArray!T(_array, v))
281         {
282             return true;
283         }
284     }
285 
286     return false;
287 }
288 
289 long pos(T)(in T[] _array, T _value)
290 {
291     foreach (k, v; _array)
292     {
293         if (v == _value)
294         {
295             return cast(long)k;
296         }
297     }
298 
299     return -1;
300 }
301 
302 T[][] combinationsRecursive(T)(in T[] data, size_t partLength)
303 {
304     if (partLength > data.length)
305     {
306         return null;
307     }
308 
309     T[][] result;
310 
311     if (partLength == 1)
312     {
313         data.each!(a => result ~= [ a ]);
314 
315         return result;
316     }
317 
318     T[] _data = data.dup;
319 
320     void recursive(ref T[][] result, in T[] t, size_t n, size_t m, T[] b, size_t M)
321     {
322         for (size_t i = n; i >= m; i--)
323         {
324             b[m - 1] = cast(T)(i - 1);
325 
326             if (m > 1)
327             {
328                 recursive(result, t, cast(T)(i - 1), cast(T)(m - 1), b, M);
329             }
330             else
331             {
332                 T[] temp = new T[M];
333 
334                 for (size_t j = 0; j < b.length; j++)
335                 {
336                     temp[j] = t[b[j]];
337                 }
338 
339                 result = temp ~ result;
340             }
341         }
342     }
343 
344     T[] temp = new T[partLength];
345     recursive(result, _data, _data.length, partLength, temp, partLength);
346 
347     return result;
348 }
349 
350 T_Value[T_Key] dupAssociativeArray(T_Value, T_Key)(T_Value[T_Key] srcArray)
351 {
352     T_Value[T_Key] ret = srcArray.dup;
353 
354     foreach (k, ref v; ret)
355     {
356         v = srcArray[k].dup;
357     }
358 
359     return ret;
360 }
361 
362 T[][] dupArrayArray(T)(T[][] srcArray)
363 {
364     T[][] ret = srcArray.dup;
365 
366     foreach (k, ref v; ret)
367     {
368         v = srcArray[k].dup;
369     }
370 
371     return ret;
372 }
373 
374 T[] dupClassArray(T)(T[] classArray)
375 {
376     T[] ret = classArray.dup;
377 
378     foreach (k, ref v; ret)
379     {
380         v = new T(classArray[k]);
381     }
382 
383     return ret;
384 }
385 
386 string compressString(const string input)
387 {
388     return compressString(cast(ubyte[]) input);
389 }
390 
391 string compressString(const scope void[] input)
392 {
393     return cast(string) compress(input);
394 }
395 
396 string uncompressString(const string input)
397 {
398     return cast(string) uncompressUbytes(input);
399 }
400 
401 ubyte[] uncompressUbytes(const string input)
402 {
403     if (input == string.init)
404     {
405         return null;
406     }
407 
408     try
409     {
410         return cast(ubyte[]) uncompress(cast(ubyte[]) input);
411     }
412     catch (Exception)
413     {
414         return null;
415     }
416 }
417 
418 
419 __gshared InsecureRandomGenerator rnd;
420 
421 struct InsecureRandomGenerator
422 {
423     private static Mt19937 generator;
424 
425     static this()
426     {
427         generator.seed(unpredictableSeed);
428     }
429 
430     T next(T = uint)(T min = T.min, T max = T.max) if (is(Unqual!T == uint) || is(Unqual!T == int) || is(Unqual!T == ubyte) || is(Unqual!T == byte) || is(Unqual!T == ulong) || is(Unqual!T == long)  || is(Unqual!T == ushort) || is(Unqual!T == short) || is(Unqual!T == size_t))
431     {
432         return uniform!("[]", T, T, typeof(generator))(min, max, generator);
433     }
434 }