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