1 /**
2 * Load/Store Operators
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *      2007 Yves Jerschow
8 *
9 * License:
10 * Botan is released under the Simplified BSD License (see LICENSE.md)
11 */
12 module botan.utils.loadstor;
13 
14 import botan.utils.types;
15 import botan.utils.bswap;
16 import botan.utils.get_byte;
17 import std.bitmanip;
18 
19 
20 /**
21 * Make a ushort from two bytes
22 * Params:
23 *  i0 = the first ubyte
24 *  i1 = the second ubyte
25 * Returns: i0 || i1
26 */
27 ushort make_ushort(ubyte i0, ubyte i1)
28 {
29     return ((cast(ushort)(i0) << 8) | i1);
30 }
31 
32 /**
33 * Make a uint from four bytes
34 * Params:
35 *  i0 = the first ubyte
36 *  i1 = the second ubyte
37 *  i2 = the third ubyte
38 *  i3 = the fourth ubyte
39 * Returns: i0 || i1 || i2 || i3
40 */
41 uint make_uint(ubyte i0, ubyte i1, ubyte i2, ubyte i3)
42 {
43     return ((cast(uint)(i0) << 24) |
44             (cast(uint)(i1) << 16) |
45             (cast(uint)(i2) <<  8) |
46             (cast(uint)(i3)));
47 }
48 
49 /**
50 * Make a ulong from eight bytes
51 * Params:
52 *  i0 = the first ubyte
53 *  i1 = the second ubyte
54 *  i2 = the third ubyte
55 *  i3 = the fourth ubyte
56 *  i4 = the fifth ubyte
57 *  i5 = the sixth ubyte
58 *  i6 = the seventh ubyte
59 *  i7 = the eighth ubyte
60 * Returns: i0 || i1 || i2 || i3 || i4 || i5 || i6 || i7
61 */
62 ulong make_ulong(ubyte i0, ubyte i1, ubyte i2, ubyte i3,
63                   ubyte i4, ubyte i5, ubyte i6, ubyte i7)
64 {
65     return   ((cast(ulong)(i0) << 56) |
66              (cast(ulong)(i1) << 48) |
67              (cast(ulong)(i2) << 40) |
68              (cast(ulong)(i3) << 32) |
69              (cast(ulong)(i4) << 24) |
70              (cast(ulong)(i5) << 16) |
71              (cast(ulong)(i6) <<  8) |
72              (cast(ulong)(i7)));
73 }
74 
75 /**
76 * Load a big-endian word
77 * Params:
78 *  input = a pointer to some bytes
79 *  off = an offset into the array
80 * Returns: off'th T of in, as a big-endian value
81 */
82 T loadBigEndian(T)(const(ubyte)* input, size_t off)
83 {
84     input += off * T.sizeof;
85     T output = 0;
86     for (size_t i = 0; i != T.sizeof; ++i)
87         output = (output << 8) | input[i];
88     return output;
89 }
90 
91 /**
92 * Load a little-endian word
93 * Params:
94 *  input = a pointer to some bytes
95 *  off = an offset into the array
96 * Returns: off'th T of in, as a litte-endian value
97 */
98 T loadLittleEndian(T)(const(ubyte)* input, size_t off)
99 {
100     input += off * T.sizeof;
101     T output = 0;
102     for (size_t i = 0; i != T.sizeof; ++i)
103         output = (output << 8) | input[T.sizeof-1-i];
104     return output;
105 }
106 
107 /**
108 * Load a big-endian ushort
109 * Params:
110 *  input = a pointer to some bytes
111 *  off = an offset into the array
112 * Returns: off'th ushort of in, as a big-endian value
113 */
114 ushort loadBigEndian(T : ushort)(const(ubyte)* input, size_t off)
115 {
116     return *cast(ushort*) nativeToBigEndian!ushort(*( (cast(const ushort*) input) + off));
117 }
118 
119 /**
120 * Load a little-endian ushort
121 * Params:
122 *  input = a pointer to some bytes
123 *  off = an offset into the array
124 * Returns: off'th ushort of in, as a little-endian value
125 */
126 ushort loadLittleEndian(T : ushort)(const(ubyte)* input, size_t off)
127 {
128     return *cast(ushort*) nativeToLittleEndian!ushort(*((cast(const ushort*) input) + off));
129 }
130 
131 /**
132 * Load a big-endian uint
133 * Params:
134 *  input = a pointer to some bytes
135 *  off = an offset into the array
136 * Returns: off'th uint of in, as a big-endian value
137 */
138 uint loadBigEndian(T : uint)(const(ubyte)* input, size_t off)
139 {
140     return *cast(uint*) nativeToBigEndian!uint(*((cast(const uint*) input) + off));
141 }
142 
143 /**
144 * Load a little-endian uint
145 * Params:
146 *  input = a pointer to some bytes
147 *  off = an offset into the array
148 * Returns: off'th uint of in, as a little-endian value
149 */
150 
151 uint loadLittleEndian(T : uint)(const(ubyte)* input, size_t off)
152 {
153     return *cast(uint*) nativeToLittleEndian!uint(*( (cast(const uint*) input) + off));
154 }
155 
156 /**
157 * Load a big-endian ulong
158 * Params:
159 *  input = a pointer to some bytes
160 *  off = an offset into the array
161 * Returns: off'th ulong of in, as a big-endian value
162 */
163 ulong loadBigEndian(T : ulong)(const(ubyte)* input, size_t off)
164 {
165     return *cast(ulong*) nativeToBigEndian!ulong(*( (cast(const ulong*) input) + off));
166     
167 }
168 
169 /**
170 * Load a little-endian ulong
171 * Params:
172 *  input = a pointer to some bytes
173 *  off = an offset into the array
174 * Returns: off'th ulong of in, as a little-endian value
175 */
176 ulong loadLittleEndian(T : ulong)(const(ubyte)* input, size_t off)
177 {
178     return *cast(ulong*) nativeToLittleEndian!ulong(*( (cast(const ulong*) input) + off));
179 }
180 
181 /**
182 * Load two little-endian words
183 * Params:
184 *  input = a pointer to some bytes
185 *  x0 = where the first word will be written
186 *  x1 = where the second word will be written
187 */
188 void loadLittleEndian(T)(const(ubyte)* input, ref T x0, ref T x1)
189 {
190     x0 = loadLittleEndian!T(input, 0);
191     x1 = loadLittleEndian!T(input, 1);
192 }
193 
194 /**
195 * Load four little-endian words
196 * Params:
197 *  input = a pointer to some bytes
198 *  x0 = where the first word will be written
199 *  x1 = where the second word will be written
200 *  x2 = where the third word will be written
201 *  x3 = where the fourth word will be written
202 */
203 void loadLittleEndian(T)(const(ubyte)* input,
204                 ref T x0, ref T x1, ref T x2, ref T x3)
205 {
206     x0 = loadLittleEndian!T(input, 0);
207     x1 = loadLittleEndian!T(input, 1);
208     x2 = loadLittleEndian!T(input, 2);
209     x3 = loadLittleEndian!T(input, 3);
210 }
211 
212 /**
213 * Load eight little-endian words
214 * Params:
215 *  input = a pointer to some bytes
216 *  x0 = where the first word will be written
217 *  x1 = where the second word will be written
218 *  x2 = where the third word will be written
219 *  x3 = where the fourth word will be written
220 *  x4 = where the fifth word will be written
221 *  x5 = where the sixth word will be written
222 *  x6 = where the seventh word will be written
223 *  x7 = where the eighth word will be written
224 */
225 void loadLittleEndian(T)(const(ubyte)* input,
226                   ref T x0, ref T x1, ref T x2, ref T x3,
227                   ref T x4, ref T x5, ref T x6, ref T x7)
228 {
229     x0 = loadLittleEndian!T(input, 0);
230     x1 = loadLittleEndian!T(input, 1);
231     x2 = loadLittleEndian!T(input, 2);
232     x3 = loadLittleEndian!T(input, 3);
233     x4 = loadLittleEndian!T(input, 4);
234     x5 = loadLittleEndian!T(input, 5);
235     x6 = loadLittleEndian!T(input, 6);
236     x7 = loadLittleEndian!T(input, 7);
237 }
238 
239 /**
240 * Load a variable number of little-endian words
241 * Params:
242 *  output = the output array of words
243 *  input = the input array of bytes
244 *  count = how many words are in in
245 */
246 void loadLittleEndian(T)(T* output, const(ubyte)* input, size_t count)
247 {
248     foreach (size_t i; 0 .. count)
249         output[i] = loadLittleEndian!T(input, i);
250 }
251 
252 /**
253 * Load two big-endian words
254 * Params:
255 *  input = a pointer to some bytes
256 *  x0 = where the first word will be written
257 *  x1 = where the second word will be written
258 */
259 void loadBigEndian(T)(const(ubyte)* input, ref T x0, ref T x1)
260 {
261     x0 = loadBigEndian!T(input, 0);
262     x1 = loadBigEndian!T(input, 1);
263 }
264 
265 /**
266 * Load four big-endian words
267 * Params:
268 *  input = a pointer to some bytes
269 *  x0 = where the first word will be written
270 *  x1 = where the second word will be written
271 *  x2 = where the third word will be written
272 *  x3 = where the fourth word will be written
273 */
274 void loadBigEndian(T)(const(ubyte)* input, ref T x0, ref T x1, ref T x2, ref T x3)
275 {
276     x0 = loadBigEndian!T(input, 0);
277     x1 = loadBigEndian!T(input, 1);
278     x2 = loadBigEndian!T(input, 2);
279     x3 = loadBigEndian!T(input, 3);
280 }
281 
282 /**
283 * Load eight big-endian words
284 * Params:
285 *  input = a pointer to some bytes
286 *  x0 = where the first word will be written
287 *  x1 = where the second word will be written
288 *  x2 = where the third word will be written
289 *  x3 = where the fourth word will be written
290 *  x4 = where the fifth word will be written
291 *  x5 = where the sixth word will be written
292 *  x6 = where the seventh word will be written
293 *  x7 = where the eighth word will be written
294 */
295 void loadBigEndian(T)(const(ubyte)* input,
296                       ref T x0, ref T x1, ref T x2, ref T x3,
297                       ref T x4, ref T x5, ref T x6, ref T x7)
298 {
299     x0 = loadBigEndian!T(input, 0);
300     x1 = loadBigEndian!T(input, 1);
301     x2 = loadBigEndian!T(input, 2);
302     x3 = loadBigEndian!T(input, 3);
303     x4 = loadBigEndian!T(input, 4);
304     x5 = loadBigEndian!T(input, 5);
305     x6 = loadBigEndian!T(input, 6);
306     x7 = loadBigEndian!T(input, 7);
307 }
308 
309 /**
310 * Load a variable number of big-endian words
311 * Params:
312 *  output = the output array of words
313 *  input = the input array of bytes
314 *  count = how many words are in in
315 */
316 void loadBigEndian(T)(T* output, const(ubyte)* input, size_t count)
317 {
318     foreach (size_t i; 0 .. count)
319         output[i] = loadBigEndian!T(input, i);
320 }
321 
322 /**
323 * Store a big-endian ushort
324 * Params:
325 *  input = the input ushort
326 *  output = the ubyte array to write to
327 */
328 void storeBigEndian(ushort input, ubyte[2]* output)
329 {
330     *cast(ushort*) output = bigEndianToNative!ushort(*cast(ubyte[2]*) &input);
331     
332 }
333 
334 /**
335 * Store a little-endian ushort
336 * Params:
337 *  input = the input ushort
338 *  output = the ubyte array to write to
339 */
340 void storeLittleEndian(ushort input, ubyte[2]* output)
341 {
342     *cast(ushort*) output = littleEndianToNative!ushort(*cast(ubyte[2]*) &input);
343     
344 }
345 
346 /**
347 * Store a big-endian uint
348 * Params:
349 *  input = the input uint
350 *  output = the ubyte array to write to
351 */
352 void storeBigEndian(uint input, ubyte[4]* output)
353 {
354     *cast(uint*) output = bigEndianToNative!uint(*cast(ubyte[4]*) &input);
355     
356 }
357 
358 /**
359 * Store a little-endian uint
360 * Params:
361 *  input = the input uint
362 *  output = the ubyte array to write to
363 */
364 void storeLittleEndian(uint input, ubyte[4]* output)
365 {
366     *cast(uint*) output = littleEndianToNative!uint(*cast(ubyte[4]*) &input);
367 
368 }
369 
370 /**
371 * Store a big-endian ulong
372 * Params:
373 *  input = the input ulong
374 *  output = the ubyte array to write to
375 */
376 void storeBigEndian(ulong input, ubyte[8]* output)
377 {
378     *cast(ulong*) output = bigEndianToNative!ulong(*cast(ubyte[8]*) &input);
379 }
380 
381 /**
382 * Store a little-endian ulong
383 * Params:
384 *  input = the input ulong
385 *  output = the ubyte array to write to
386 */
387 void storeLittleEndian(in ulong input, ubyte[8]* output)
388 {
389     *cast(ulong*) output = littleEndianToNative!ulong(*cast(ubyte[8]*) &input);
390 }
391 
392 /**
393 * Store a little-endian ulong
394 * Params:
395 *  input = the input ulong
396 *  output = the ubyte array to write to
397 */
398 void storeLittleEndian(T)(in T input, ubyte* output)
399 {
400     storeLittleEndian(cast(T) input, cast(ubyte[T.sizeof]*) output);
401 }
402 
403 /**
404 * Store a big-endian ulong
405 * Params:
406 *  input = the input ulong
407 *  output = the ubyte array to write to
408 */
409 void storeBigEndian(T)(in T input, ubyte* output)
410 {
411     storeBigEndian(cast(T) input, cast(ubyte[T.sizeof]*) output);
412 }
413 
414 /**
415 * Store two little-endian words
416 * Params:
417 *  output = the output ubyte array
418 *  x0 = the first word
419 *  x1 = the second word
420 */
421 void storeLittleEndian(T)(ubyte* output, T x0, T x1)
422 {
423     storeLittleEndian(x0, output + (0 * T.sizeof));
424     storeLittleEndian(x1, output + (1 * T.sizeof));
425 }
426 
427 /**
428 * Store two big-endian words
429 * Params:
430 *  output = the output ubyte array
431 *  x0 = the first word
432 *  x1 = the second word
433 */
434 void storeBigEndian(T)(ubyte* output, T x0, T x1)
435 {
436     storeBigEndian(x0, output + (0 * T.sizeof));
437     storeBigEndian(x1, output + (1 * T.sizeof));
438 }
439 
440 /**
441 * Store four little-endian words
442 * Params:
443 *  output = the output ubyte array
444 *  x0 = the first word
445 *  x1 = the second word
446 *  x2 = the third word
447 *  x3 = the fourth word
448 */
449 void storeLittleEndian(T)(ubyte* output, T x0, T x1, T x2, T x3)
450 {
451     storeLittleEndian(x0, output + (0 * T.sizeof));
452     storeLittleEndian(x1, output + (1 * T.sizeof));
453     storeLittleEndian(x2, output + (2 * T.sizeof));
454     storeLittleEndian(x3, output + (3 * T.sizeof));
455 }
456 
457 /**
458 * Store four big-endian words
459 * Params:
460 *  output = the output ubyte array
461 *  x0 = the first word
462 *  x1 = the second word
463 *  x2 = the third word
464 *  x3 = the fourth word
465 */
466 void storeBigEndian(T)(ref ubyte* output, T x0, T x1, T x2, T x3)
467 {
468     storeBigEndian(x0, output + (0 * T.sizeof));
469     storeBigEndian(x1, output + (1 * T.sizeof));
470     storeBigEndian(x2, output + (2 * T.sizeof));
471     storeBigEndian(x3, output + (3 * T.sizeof));
472 }
473 
474 /**
475 * Store eight little-endian words
476 * Params:
477 *  output = the output ubyte array
478 *  x0 = the first word
479 *  x1 = the second word
480 *  x2 = the third word
481 *  x3 = the fourth word
482 *  x4 = the fifth word
483 *  x5 = the sixth word
484 *  x6 = the seventh word
485 *  x7 = the eighth word
486 */
487 void storeLittleEndian(T)(ubyte* output, T x0, T x1, T x2, T x3,
488                                 T x4, T x5, T x6, T x7)
489 {
490     storeLittleEndian(x0, output + (0 * T.sizeof));
491     storeLittleEndian(x1, output + (1 * T.sizeof));
492     storeLittleEndian(x2, output + (2 * T.sizeof));
493     storeLittleEndian(x3, output + (3 * T.sizeof));
494     storeLittleEndian(x4, output + (4 * T.sizeof));
495     storeLittleEndian(x5, output + (5 * T.sizeof));
496     storeLittleEndian(x6, output + (6 * T.sizeof));
497     storeLittleEndian(x7, output + (7 * T.sizeof));
498 }
499 
500 /**
501 * Store eight big-endian words
502 * Params:
503 *  output = the output ubyte array
504 *  x0 = the first word
505 *  x1 = the second word
506 *  x2 = the third word
507 *  x3 = the fourth word
508 *  x4 = the fifth word
509 *  x5 = the sixth word
510 *  x6 = the seventh word
511 *  x7 = the eighth word
512 */
513 void storeBigEndian(T)(ubyte* output, T x0, T x1, T x2, T x3,
514                                 T x4, T x5, T x6, T x7)
515 {
516     storeBigEndian(x0, output + (0 * T.sizeof));
517     storeBigEndian(x1, output + (1 * T.sizeof));
518     storeBigEndian(x2, output + (2 * T.sizeof));
519     storeBigEndian(x3, output + (3 * T.sizeof));
520     storeBigEndian(x4, output + (4 * T.sizeof));
521     storeBigEndian(x5, output + (5 * T.sizeof));
522     storeBigEndian(x6, output + (6 * T.sizeof));
523     storeBigEndian(x7, output + (7 * T.sizeof));
524 }