1 // Written in D programming language
2 /**
3 *   Utilities to convert hex strings to numbers.
4 *   Authors : David L. 'SpottedTiger' Davis
5 *   Licence : Public Domain / Contributed to Digital Mars
6 */
7 module pgator.util.hexconv;
8 
9 /// Hex string to an unsigned decimal whole number 
10 /**
11 *   Converts a Hex string from 0x0 to 0xFFFFFFFFFFFFFF
12 *   into a ulong value 0 to 18,446,744,073,709,551,615
13 *   also it handles the lowercase 'a' thru 'f'.
14 *
15 *   Authors  : David 'SpottedTiger' L. Davis
16 *   Created  : 03.May.05
17 *
18 *   Example:
19 *   ----------
20 *   ulong ul;
21 *
22 *   ul = xtoul("0"c); 
23 *   assert( ul == 0x0 );
24 *   ul = xtoul("FF"c); 
25 *   assert( ul == 0xFF );
26 *   ul = xtoul("eea"c); 
27 *   assert( ul == 0xEEA );
28 *   ul = xtoul("AB"c);
29 *   assert( ul == 0xAB );
30 *   ul = xtoul("ABCD"c);
31 *   assert( ul == 0xABCD );
32 *   ul = xtoul("A12CD00"c);
33 *   assert( ul == 0xA12CD00 );
34 *   ul = xtoul("FFFFFFFFFFFFFFFF"c); 
35 *   assert( ul == 0xFFFFFFFFFFFFFFFF );
36 *   ----------
37 */
38 ulong xtoul(string sx)
39 {
40    ulong  ul = 0L;
41    int    j = 7;
42    char   c, c1, c2;
43    char[] st  = cast(char[])sx;
44    size_t len = st.length;
45    
46    const char[] zeros = "0000000000000000"c;
47    union u { ulong ul; char[8] c; }
48    
49    u U;
50    
51    if (len == 0 || len > 16)
52        throw new Exception( "xtoul() the string parameter is either an empty string,"c ~
53                             " or its length is greater than 16 characters."c );
54     
55    // isHex()                         
56    for (int i = 0; i < st.length; i++)                             
57    {
58        //c = ( sx[i] > 'F' ? sx[i] - 32 : sx[i] );
59        c = st[i];
60 
61        if ((c >= '0' && c <= '9') || 
62            (c >= 'A' && c <= 'F') ||
63            (c >= 'a' && c <= 'f'))
64           continue;
65        else     
66          throw new Exception("xtoul() invalid hex character used."c);   
67    }
68          
69    if (len < 16)
70        st = zeros[0..16 - len] ~ st;
71    
72    j = 7;
73    for (int i = 0; i < 16; i += 2)
74    {
75        c1 = (st[i] > 'F' ? cast(char)(st[i] - 32) : st[i]); 
76        c2 = (st[i + 1] > 'F' ? cast(char)(st[i + 1] - 32) : st[i + 1]);
77        c1 = cast(char)(cast(int)(c1 > 52 ? c1 - 55 : c1 - 48) << 4);
78        U.c[j--] = cast(char)(c1 + (c2 > 52 ? c2 - 55 : c2 - 48));
79    }
80 
81    return U.ul;
82 } 
83 
84 unittest
85 {
86    ulong ul;
87 
88    ul = xtoul("0"c); 
89    assert( ul == 0x0 );
90    ul = xtoul("FF"c); 
91    assert( ul == 0xFF );
92    ul = xtoul("eea"c); 
93    assert( ul == 0xEEA );
94    ul = xtoul("AB"c);
95    assert( ul == 0xAB );
96    ul = xtoul("ABCD"c);
97    assert( ul == 0xABCD );
98    ul = xtoul("A12CD00"c);
99    assert( ul == 0xA12CD00 );
100    ul = xtoul("FFFFFFFFFFFFFFFF"c); 
101    assert( ul == 0xFFFFFFFFFFFFFFFF );
102 }
103 
104 /// Decimal unsigned whole number to Hex string
105 /**
106 *   Accepts any positive number from 0 to 18,446,744,073,709,551,615
107 *   and the returns an even number of hex strings up to 16 characters
108 *   (from 0x0 to 0xFFFFFFFFFFFFFF).
109 *
110 *   Authors  : David 'SpottedTiger' L. Davis
111 *   Created  : 04.May.05
112 *
113 *   Example:
114 *   ---------
115 *   string sx;
116 *
117 *   sx = ultox(0); //0x0
118 *   assert( sx == "00"c );
119 *
120 *   sx = ultox(255); //0xFF
121 *   assert( sx == "FF"c );
122 *   sx = ultox(171); //0xAB
123 *   assert( sx == "AB"c );
124 *   sx = ultox(43981); //0xABCD
125 *   assert( sx == "ABCD"c );
126 *   sx = ultox(169004288); //0xA12CD00
127 *   assert( sx == "0A12CD00"c );
128 *   sx = ultox(0xA12CD00); //169004288
129 *   assert( sx == "0A12CD00"c );
130 * 
131 *   sx = ultox(ulong.max); //0xFFFFFFFFFFFFFFFF
132 *   assert( sx == "FFFFFFFFFFFFFFFF"c );
133 *   ---------
134 */
135 string ultox(in ulong ul)
136 {
137    char[16] sx;
138    char     c1, c2;
139    union    u { ulong ul; char[8] c; }
140    int      i = 0, j = 0, k = 0;
141    bool     z = true;
142    u U;
143 
144    U.ul = ul;
145    
146    for (i = 7; i >= 0; i--)
147    {
148        c1 = U.c[i] >> 4;
149        c1 = cast(char)(c1 > 9 ? c1 + 55 : c1 + 48);
150        c2 = U.c[i] & 0x0F;
151        c2 = cast(char)(c2 > 9 ? c2 + 55 : c2 + 48);
152        
153        if (z && c1 == '0' && c2 == '0')
154            continue;
155 
156        z = false;
157        sx[j++] = c1;
158        sx[j++] = c2;
159    }
160    
161    if (j > 0)
162        //Copying a fixed array into a dynamic array, must COW.
163        return sx[0..j].dup;
164    else
165        return "00"c;    
166 }
167 
168 unittest
169 {
170    string sx;
171 
172    sx = ultox(0); //0x0
173    assert( sx == "00"c );
174 
175    sx = ultox(255); //0xFF
176    assert( sx == "FF"c );
177    sx = ultox(171); //0xAB
178    assert( sx == "AB"c );
179    sx = ultox(43981); //0xABCD
180    assert( sx == "ABCD"c );
181    sx = ultox(169004288); //0xA12CD00
182    assert( sx == "0A12CD00"c );
183    sx = ultox(0xA12CD00); //169004288
184    assert( sx == "0A12CD00"c );
185   
186    sx = ultox(ulong.max); //0xFFFFFFFFFFFFFFFF
187    assert( sx == "FFFFFFFFFFFFFFFF"c );
188 }
189 
190 /// Checks if string contains hex number
191 /**
192 *   Authors  : David 'SpottedTiger' L. Davis
193 *   Created  : 04.May.05
194 *
195 *   Example:
196 *   -----------
197 *   assert( isHex("00"c) );
198 *   assert( isHex("FF"c) );
199 *   assert( isHex("Ffae0"c) );
200 *   assert( isHex("AB"c) );
201 *   assert( isHex("abdef"c) );
202 *   assert( isHex("ABCD"c) );
203 *   assert( isHex("0A12CD00"c) );
204 *   assert( isHex("FFFFFFFFFFFFFFFF"c) );
205 *  
206 *   assert( isHex("00ER"c) == false );
207 *   assert( !isHex("0xW"c) );
208 *   -----------
209 */
210 bool isHex(string sx)   
211 {          
212    char c;
213                
214    for (int i = 0; i < sx.length; i++)                             
215    {
216        c = sx[i];
217        
218        if ((c >= '0' && c <= '9') || 
219            (c >= 'A' && c <= 'F') ||
220            (c >= 'a' && c <= 'f'))
221            continue;
222        else     
223            return false;   
224    }
225    
226    return true;
227 }
228 
229 unittest
230 {
231    assert( isHex("00"c) );
232    assert( isHex("FF"c) );
233    assert( isHex("Ffae0"c) );
234    assert( isHex("AB"c) );
235    assert( isHex("abdef"c) );
236    assert( isHex("ABCD"c) );
237    assert( isHex("0A12CD00"c) );
238    assert( isHex("FFFFFFFFFFFFFFFF"c) );
239    
240    assert( isHex("00ER"c) == false );
241    assert( !isHex("0xW"c) );
242 }