1 module tagion.utils.Miscellaneous;
2 
3 import std.algorithm;
4 import std.array;
5 import std.range;
6 import std.exception;
7 import std.range.primitives : isInputRange;
8 import tagion.basic.Types : Buffer, isBufferType;
9 import tagion.basic.tagionexceptions : TagionException;
10 
11 enum HEX_SEPARATOR = '_';
12 
13 @safe Buffer decode(const(char[]) hex) pure {
14     if (hex.replace(HEX_SEPARATOR, "").length % 2 != 0) {
15         throw new TagionException("Hex string length not even");
16     }
17     int to_hex(const(char) c) {
18         if ((c >= '0') && (c <= '9')) {
19             return cast(ubyte)(c - '0');
20         }
21         else if ((c >= 'a') && (c <= 'f')) {
22             return c - 'a' + 10;
23         }
24         else if ((c >= 'A') && (c <= 'F')) {
25             return cast(ubyte)(c - 'A') + 10;
26         }
27         throw new TagionException("Bad char '" ~ c ~ "'");
28     }
29 
30     immutable buf_size = hex.length / 2;
31     ubyte[] result = new ubyte[buf_size];
32     uint j;
33     bool event;
34     ubyte part;
35     foreach (c; hex) {
36         if (c != HEX_SEPARATOR) {
37             part <<= 4;
38             part |= to_hex(c);
39 
40             if (event) {
41                 result[j] = part;
42                 part = 0;
43                 j++;
44             }
45             event = !event;
46         }
47     }
48     return result.idup;
49 }
50 
51 /++
52  + Converts on the first part of the buffer to a Hex string
53  + Used for debugging
54  +
55  + Params:
56  +     buf = is a buffer type like a byte array
57  + Returns:
58  +     The 16 first hex digits of the buffer
59 +/
60 @safe
61 string cutHex(BUF)(BUF buf) pure if (isBufferType!BUF) {
62     import std.format;
63     import std.algorithm : min;
64 
65     enum LEN = ulong.sizeof;
66     return format!"%(%02x%)"(buf[0 .. min(LEN, buf.length)]);
67 }
68 
69 @safe
70 Buffer xor(scope const(ubyte[]) a, scope const(ubyte[]) b) pure nothrow
71 in {
72     assert(a.length == b.length);
73     assert(a.length % ulong.sizeof == 0);
74 }
75 do {
76     import tagion.utils.Gene : gene_xor;
77 
78     const _a = cast(const(ulong[])) a;
79     const _b = cast(const(ulong[])) b;
80     return (() @trusted => cast(Buffer) gene_xor(_a, _b))();
81 }
82 
83 @nogc @safe
84 void xor(ref scope ubyte[] result, scope const(ubyte[]) a, scope const(ubyte[]) b) pure nothrow
85 in {
86     assert(a.length == b.length);
87     assert(a.length % ulong.sizeof == 0);
88 }
89 do {
90     import tagion.utils.Gene : gene_xor;
91 
92     const _a = cast(const(ulong[])) a;
93     const _b = cast(const(ulong[])) b;
94     auto _result = cast(ulong[]) result;
95     gene_xor(_result, _a, _b);
96 }
97 
98 @safe
99 Buffer xor(Range)(scope Range range) pure if (isInputRange!Range && is(ElementType!Range : const(ubyte[])))
100 in (!range.empty)
101 do {
102     import std.array : array;
103     import std.range : tail;
104 
105     scope result = new ubyte[range.front.length];
106     range.each!((rhs) => xor(result, result, rhs));
107     return result.idup;
108 }