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 }