1 /**
2 * This file is part of the dcrypt project.
3 *
4 * Copyright:
5 * Copyright (C) dcrypt contributors 2009.
6 * Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
7 * All rights reserved.
8 *
9 * License:
10 * Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
11 * See LICENSE_TANGO.txt for details.
12 *
13 * Authors: Thomas Dixon
14 *
15 */
16
17 module ocean.util.cipher.misc.ByteConverter;
18
19 import ocean.meta.types.Qualifiers;
20
21 version (unittest)
22 {
23 import ocean.core.Test;
24 }
25
26 /** Converts between integral types and unsigned byte arrays */
27 struct ByteConverter
28 {
29 private enum istring hexits = "0123456789abcdef";
30
31 /** Conversions between little endian integrals and bytes */
32 struct LittleEndian
33 {
34 /**
35 * Converts the supplied array to integral type T
36 *
37 * Params:
38 * x_ = The supplied array of bytes (ubytes, bytes, chars, whatever)
39 *
40 * Returns:
41 * A integral of type T created with the supplied bytes placed
42 * in the specified byte order.
43 */
44 static T to (T) (const(void)[] x_)
45 {
46 auto x = cast(const(ubyte)[])x_;
47
48 T result = ((x[0] & 0xff) |
49 ((x[1] & 0xff) << 8));
50
51 static if (T.sizeof >= int.sizeof)
52 {
53 result |= ((x[2] & 0xff) << 16) |
54 ((x[3] & 0xff) << 24);
55 }
56
57 static if (T.sizeof >= long.sizeof)
58 {
59 result |= (cast(T)(x[4] & 0xff) << 32) |
60 (cast(T)(x[5] & 0xff) << 40) |
61 (cast(T)(x[6] & 0xff) << 48) |
62 (cast(T)(x[7] & 0xff) << 56);
63 }
64
65 return result;
66 }
67
68 /**
69 * Converts the supplied integral to an array of unsigned bytes.
70 *
71 * Params:
72 * input = Integral to convert to bytes
73 *
74 * Returns:
75 * Integral input of type T split into its respective bytes
76 * with the bytes placed in the specified byte order.
77 */
78 static ubyte[] from (T) (const(T) input)
79 {
80 ubyte[] output = new ubyte[T.sizeof];
81
82 output[0] = cast(ubyte)(input);
83 output[1] = cast(ubyte)(input >> 8);
84
85 static if (T.sizeof >= int.sizeof)
86 {
87 output[2] = cast(ubyte)(input >> 16);
88 output[3] = cast(ubyte)(input >> 24);
89 }
90
91 static if (T.sizeof >= long.sizeof)
92 {
93 output[4] = cast(ubyte)(input >> 32);
94 output[5] = cast(ubyte)(input >> 40);
95 output[6] = cast(ubyte)(input >> 48);
96 output[7] = cast(ubyte)(input >> 56);
97 }
98
99 return output;
100 }
101 }
102
103 /** Conversions between big endian integrals and bytes */
104 struct BigEndian
105 {
106
107 static T to (T) (const(void)[] x_)
108 {
109 auto x = cast(const(ubyte)[])x_;
110
111 static if (is(T == ushort) || is(T == short))
112 {
113 return cast(T) (((x[0] & 0xff) << 8) |
114 (x[1] & 0xff));
115 }
116 else static if (is(T == uint) || is(T == int))
117 {
118 return cast(T) (((x[0] & 0xff) << 24) |
119 ((x[1] & 0xff) << 16) |
120 ((x[2] & 0xff) << 8) |
121 (x[3] & 0xff));
122 }
123 else static if (is(T == ulong) || is(T == long))
124 {
125 return cast(T) ((cast(T)(x[0] & 0xff) << 56) |
126 (cast(T)(x[1] & 0xff) << 48) |
127 (cast(T)(x[2] & 0xff) << 40) |
128 (cast(T)(x[3] & 0xff) << 32) |
129 ((x[4] & 0xff) << 24) |
130 ((x[5] & 0xff) << 16) |
131 ((x[6] & 0xff) << 8) |
132 (x[7] & 0xff));
133 }
134 }
135
136 static ubyte[] from(T)(T input)
137 {
138 ubyte[] output = new ubyte[T.sizeof];
139
140 static if (T.sizeof == long.sizeof)
141 {
142 output[0] = cast(ubyte)(input >> 56);
143 output[1] = cast(ubyte)(input >> 48);
144 output[2] = cast(ubyte)(input >> 40);
145 output[3] = cast(ubyte)(input >> 32);
146 output[4] = cast(ubyte)(input >> 24);
147 output[5] = cast(ubyte)(input >> 16);
148 output[6] = cast(ubyte)(input >> 8);
149 output[7] = cast(ubyte)(input);
150 }
151 else static if (T.sizeof == int.sizeof)
152 {
153 output[0] = cast(ubyte)(input >> 24);
154 output[1] = cast(ubyte)(input >> 16);
155 output[2] = cast(ubyte)(input >> 8);
156 output[3] = cast(ubyte)(input);
157 }
158 else static if (T.sizeof == short.sizeof)
159 {
160 output[0] = cast(ubyte)(input >> 8);
161 output[1] = cast(ubyte)(input);
162 }
163
164 return output;
165 }
166 }
167
168 /**
169 * Takes an array and converts each byte to its hex representation.
170 *
171 * Params:
172 * input_ = the array of bytes to represent
173 *
174 * Returns:
175 * A newed char[] containing the hex digits representing the
176 * input
177 */
178
179 static mstring hexEncode(const(void)[] input_)
180 {
181 mstring buffer;
182
183 return(hexEncode(input_, buffer));
184 }
185
186 /**
187 * Takes an array and converts each byte to its hex representation.
188 *
189 * Params:
190 * input_ = the array of bytes to represent
191 * output = the buffer into which the results will be written
192 *
193 * Returns:
194 * A slice of output containing the hex digits representing the
195 * input
196 */
197
198 static mstring hexEncode(const(void)[] input_, ref mstring output)
199 {
200 auto input = cast(const(ubyte)[])input_;
201 // make sure our buffer is big enough (2 hex digits per byte).
202 output.length = input.length * 2;
203
204 int i = 0;
205 foreach (ubyte j; input)
206 {
207 output[i++] = hexits[j>>4];
208 output[i++] = hexits[j&0xf];
209 }
210
211 return output;
212 }
213
214 unittest
215 {
216 mstring buffer;
217
218 test!("==")(hexEncode(cast(ubyte[])([
219 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
220 ]), buffer), "0123456789abcdef"[]);
221 // check the right amount of memory was allocated
222 test!("==")(buffer.length, 16);
223 }
224
225 static ubyte[] hexDecode(cstring input)
226 {
227 cstring inputAsLower = stringToLower(input);
228 ubyte[] output = new ubyte[input.length>>1];
229
230 static ubyte[char] hexitIndex;
231 for (ubyte i = 0; i < hexits.length; i++)
232 hexitIndex[hexits[i]] = i;
233
234 for (int i = 0, j = 0; i < output.length; i++)
235 {
236 output[i] = cast(ubyte) (hexitIndex[inputAsLower[j++]] << 4);
237 output[i] |= hexitIndex[inputAsLower[j++]];
238 }
239
240 return output;
241 }
242
243 private static mstring stringToLower(cstring input)
244 {
245 mstring output = new char[input.length];
246
247 foreach (size_t i, char c; input)
248 output[i] = cast(ubyte) ((c >= 'A' && c <= 'Z') ? c+32 : c);
249
250 return output;
251 }
252 }