Botan  1.11.15
src/lib/utils/loadstor.h
Go to the documentation of this file.
00001 /*
00002 * Load/Store Operators
00003 * (C) 1999-2007 Jack Lloyd
00004 *     2007 Yves Jerschow
00005 *
00006 * Botan is released under the Simplified BSD License (see license.txt)
00007 */
00008 
00009 #ifndef BOTAN_LOAD_STORE_H__
00010 #define BOTAN_LOAD_STORE_H__
00011 
00012 #include <botan/types.h>
00013 #include <botan/bswap.h>
00014 #include <botan/get_byte.h>
00015 #include <botan/mem_ops.h>
00016 #include <vector>
00017 
00018 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00019 
00020 #if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
00021 
00022 #define BOTAN_ENDIAN_N2B(x) (x)
00023 #define BOTAN_ENDIAN_B2N(x) (x)
00024 
00025 #define BOTAN_ENDIAN_N2L(x) reverse_bytes(x)
00026 #define BOTAN_ENDIAN_L2N(x) reverse_bytes(x)
00027 
00028 #elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
00029 
00030 #define BOTAN_ENDIAN_N2L(x) (x)
00031 #define BOTAN_ENDIAN_L2N(x) (x)
00032 
00033 #define BOTAN_ENDIAN_N2B(x) reverse_bytes(x)
00034 #define BOTAN_ENDIAN_B2N(x) reverse_bytes(x)
00035 
00036 #endif
00037 
00038 #endif
00039 
00040 namespace Botan {
00041 
00042 /**
00043 * Make a u16bit from two bytes
00044 * @param i0 the first byte
00045 * @param i1 the second byte
00046 * @return i0 || i1
00047 */
00048 inline u16bit make_u16bit(byte i0, byte i1)
00049    {
00050    return ((static_cast<u16bit>(i0) << 8) | i1);
00051    }
00052 
00053 /**
00054 * Make a u32bit from four bytes
00055 * @param i0 the first byte
00056 * @param i1 the second byte
00057 * @param i2 the third byte
00058 * @param i3 the fourth byte
00059 * @return i0 || i1 || i2 || i3
00060 */
00061 inline u32bit make_u32bit(byte i0, byte i1, byte i2, byte i3)
00062    {
00063    return ((static_cast<u32bit>(i0) << 24) |
00064            (static_cast<u32bit>(i1) << 16) |
00065            (static_cast<u32bit>(i2) <<  8) |
00066            (static_cast<u32bit>(i3)));
00067    }
00068 
00069 /**
00070 * Make a u32bit from eight bytes
00071 * @param i0 the first byte
00072 * @param i1 the second byte
00073 * @param i2 the third byte
00074 * @param i3 the fourth byte
00075 * @param i4 the fifth byte
00076 * @param i5 the sixth byte
00077 * @param i6 the seventh byte
00078 * @param i7 the eighth byte
00079 * @return i0 || i1 || i2 || i3 || i4 || i5 || i6 || i7
00080 */
00081 inline u64bit make_u64bit(byte i0, byte i1, byte i2, byte i3,
00082                           byte i4, byte i5, byte i6, byte i7)
00083     {
00084    return ((static_cast<u64bit>(i0) << 56) |
00085            (static_cast<u64bit>(i1) << 48) |
00086            (static_cast<u64bit>(i2) << 40) |
00087            (static_cast<u64bit>(i3) << 32) |
00088            (static_cast<u64bit>(i4) << 24) |
00089            (static_cast<u64bit>(i5) << 16) |
00090            (static_cast<u64bit>(i6) <<  8) |
00091            (static_cast<u64bit>(i7)));
00092     }
00093 
00094 /**
00095 * Load a big-endian word
00096 * @param in a pointer to some bytes
00097 * @param off an offset into the array
00098 * @return off'th T of in, as a big-endian value
00099 */
00100 template<typename T>
00101 inline T load_be(const byte in[], size_t off)
00102    {
00103    in += off * sizeof(T);
00104    T out = 0;
00105    for(size_t i = 0; i != sizeof(T); ++i)
00106       out = (out << 8) | in[i];
00107    return out;
00108    }
00109 
00110 /**
00111 * Load a little-endian word
00112 * @param in a pointer to some bytes
00113 * @param off an offset into the array
00114 * @return off'th T of in, as a litte-endian value
00115 */
00116 template<typename T>
00117 inline T load_le(const byte in[], size_t off)
00118    {
00119    in += off * sizeof(T);
00120    T out = 0;
00121    for(size_t i = 0; i != sizeof(T); ++i)
00122       out = (out << 8) | in[sizeof(T)-1-i];
00123    return out;
00124    }
00125 
00126 /**
00127 * Load a big-endian u16bit
00128 * @param in a pointer to some bytes
00129 * @param off an offset into the array
00130 * @return off'th u16bit of in, as a big-endian value
00131 */
00132 template<>
00133 inline u16bit load_be<u16bit>(const byte in[], size_t off)
00134    {
00135 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00136    return BOTAN_ENDIAN_N2B(*(reinterpret_cast<const u16bit*>(in) + off));
00137 #else
00138    in += off * sizeof(u16bit);
00139    return make_u16bit(in[0], in[1]);
00140 #endif
00141    }
00142 
00143 /**
00144 * Load a little-endian u16bit
00145 * @param in a pointer to some bytes
00146 * @param off an offset into the array
00147 * @return off'th u16bit of in, as a little-endian value
00148 */
00149 template<>
00150 inline u16bit load_le<u16bit>(const byte in[], size_t off)
00151    {
00152 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00153    return BOTAN_ENDIAN_N2L(*(reinterpret_cast<const u16bit*>(in) + off));
00154 #else
00155    in += off * sizeof(u16bit);
00156    return make_u16bit(in[1], in[0]);
00157 #endif
00158    }
00159 
00160 /**
00161 * Load a big-endian u32bit
00162 * @param in a pointer to some bytes
00163 * @param off an offset into the array
00164 * @return off'th u32bit of in, as a big-endian value
00165 */
00166 template<>
00167 inline u32bit load_be<u32bit>(const byte in[], size_t off)
00168    {
00169 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00170    return BOTAN_ENDIAN_N2B(*(reinterpret_cast<const u32bit*>(in) + off));
00171 #else
00172    in += off * sizeof(u32bit);
00173    return make_u32bit(in[0], in[1], in[2], in[3]);
00174 #endif
00175    }
00176 
00177 /**
00178 * Load a little-endian u32bit
00179 * @param in a pointer to some bytes
00180 * @param off an offset into the array
00181 * @return off'th u32bit of in, as a little-endian value
00182 */
00183 template<>
00184 inline u32bit load_le<u32bit>(const byte in[], size_t off)
00185    {
00186 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00187    return BOTAN_ENDIAN_N2L(*(reinterpret_cast<const u32bit*>(in) + off));
00188 #else
00189    in += off * sizeof(u32bit);
00190    return make_u32bit(in[3], in[2], in[1], in[0]);
00191 #endif
00192    }
00193 
00194 /**
00195 * Load a big-endian u64bit
00196 * @param in a pointer to some bytes
00197 * @param off an offset into the array
00198 * @return off'th u64bit of in, as a big-endian value
00199 */
00200 template<>
00201 inline u64bit load_be<u64bit>(const byte in[], size_t off)
00202    {
00203 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00204    return BOTAN_ENDIAN_N2B(*(reinterpret_cast<const u64bit*>(in) + off));
00205 #else
00206    in += off * sizeof(u64bit);
00207    return make_u64bit(in[0], in[1], in[2], in[3],
00208                       in[4], in[5], in[6], in[7]);
00209 #endif
00210    }
00211 
00212 /**
00213 * Load a little-endian u64bit
00214 * @param in a pointer to some bytes
00215 * @param off an offset into the array
00216 * @return off'th u64bit of in, as a little-endian value
00217 */
00218 template<>
00219 inline u64bit load_le<u64bit>(const byte in[], size_t off)
00220    {
00221 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00222    return BOTAN_ENDIAN_N2L(*(reinterpret_cast<const u64bit*>(in) + off));
00223 #else
00224    in += off * sizeof(u64bit);
00225    return make_u64bit(in[7], in[6], in[5], in[4],
00226                       in[3], in[2], in[1], in[0]);
00227 #endif
00228    }
00229 
00230 /**
00231 * Load two little-endian words
00232 * @param in a pointer to some bytes
00233 * @param x0 where the first word will be written
00234 * @param x1 where the second word will be written
00235 */
00236 template<typename T>
00237 inline void load_le(const byte in[], T& x0, T& x1)
00238    {
00239    x0 = load_le<T>(in, 0);
00240    x1 = load_le<T>(in, 1);
00241    }
00242 
00243 /**
00244 * Load four little-endian words
00245 * @param in a pointer to some bytes
00246 * @param x0 where the first word will be written
00247 * @param x1 where the second word will be written
00248 * @param x2 where the third word will be written
00249 * @param x3 where the fourth word will be written
00250 */
00251 template<typename T>
00252 inline void load_le(const byte in[],
00253                     T& x0, T& x1, T& x2, T& x3)
00254    {
00255    x0 = load_le<T>(in, 0);
00256    x1 = load_le<T>(in, 1);
00257    x2 = load_le<T>(in, 2);
00258    x3 = load_le<T>(in, 3);
00259    }
00260 
00261 /**
00262 * Load eight little-endian words
00263 * @param in a pointer to some bytes
00264 * @param x0 where the first word will be written
00265 * @param x1 where the second word will be written
00266 * @param x2 where the third word will be written
00267 * @param x3 where the fourth word will be written
00268 * @param x4 where the fifth word will be written
00269 * @param x5 where the sixth word will be written
00270 * @param x6 where the seventh word will be written
00271 * @param x7 where the eighth word will be written
00272 */
00273 template<typename T>
00274 inline void load_le(const byte in[],
00275                     T& x0, T& x1, T& x2, T& x3,
00276                     T& x4, T& x5, T& x6, T& x7)
00277    {
00278    x0 = load_le<T>(in, 0);
00279    x1 = load_le<T>(in, 1);
00280    x2 = load_le<T>(in, 2);
00281    x3 = load_le<T>(in, 3);
00282    x4 = load_le<T>(in, 4);
00283    x5 = load_le<T>(in, 5);
00284    x6 = load_le<T>(in, 6);
00285    x7 = load_le<T>(in, 7);
00286    }
00287 
00288 /**
00289 * Load a variable number of little-endian words
00290 * @param out the output array of words
00291 * @param in the input array of bytes
00292 * @param count how many words are in in
00293 */
00294 template<typename T>
00295 inline void load_le(T out[],
00296                     const byte in[],
00297                     size_t count)
00298    {
00299 #if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS)
00300    std::memcpy(out, in, sizeof(T)*count);
00301 
00302 #if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
00303    const size_t blocks = count - (count % 4);
00304    const size_t left = count - blocks;
00305 
00306    for(size_t i = 0; i != blocks; i += 4)
00307       bswap_4(out + i);
00308 
00309    for(size_t i = 0; i != left; ++i)
00310       out[blocks+i] = reverse_bytes(out[blocks+i]);
00311 #endif
00312 
00313 #else
00314    for(size_t i = 0; i != count; ++i)
00315       out[i] = load_le<T>(in, i);
00316 #endif
00317    }
00318 
00319 /**
00320 * Load two big-endian words
00321 * @param in a pointer to some bytes
00322 * @param x0 where the first word will be written
00323 * @param x1 where the second word will be written
00324 */
00325 template<typename T>
00326 inline void load_be(const byte in[], T& x0, T& x1)
00327    {
00328    x0 = load_be<T>(in, 0);
00329    x1 = load_be<T>(in, 1);
00330    }
00331 
00332 /**
00333 * Load four big-endian words
00334 * @param in a pointer to some bytes
00335 * @param x0 where the first word will be written
00336 * @param x1 where the second word will be written
00337 * @param x2 where the third word will be written
00338 * @param x3 where the fourth word will be written
00339 */
00340 template<typename T>
00341 inline void load_be(const byte in[],
00342                     T& x0, T& x1, T& x2, T& x3)
00343    {
00344    x0 = load_be<T>(in, 0);
00345    x1 = load_be<T>(in, 1);
00346    x2 = load_be<T>(in, 2);
00347    x3 = load_be<T>(in, 3);
00348    }
00349 
00350 /**
00351 * Load eight big-endian words
00352 * @param in a pointer to some bytes
00353 * @param x0 where the first word will be written
00354 * @param x1 where the second word will be written
00355 * @param x2 where the third word will be written
00356 * @param x3 where the fourth word will be written
00357 * @param x4 where the fifth word will be written
00358 * @param x5 where the sixth word will be written
00359 * @param x6 where the seventh word will be written
00360 * @param x7 where the eighth word will be written
00361 */
00362 template<typename T>
00363 inline void load_be(const byte in[],
00364                     T& x0, T& x1, T& x2, T& x3,
00365                     T& x4, T& x5, T& x6, T& x7)
00366    {
00367    x0 = load_be<T>(in, 0);
00368    x1 = load_be<T>(in, 1);
00369    x2 = load_be<T>(in, 2);
00370    x3 = load_be<T>(in, 3);
00371    x4 = load_be<T>(in, 4);
00372    x5 = load_be<T>(in, 5);
00373    x6 = load_be<T>(in, 6);
00374    x7 = load_be<T>(in, 7);
00375    }
00376 
00377 /**
00378 * Load a variable number of big-endian words
00379 * @param out the output array of words
00380 * @param in the input array of bytes
00381 * @param count how many words are in in
00382 */
00383 template<typename T>
00384 inline void load_be(T out[],
00385                     const byte in[],
00386                     size_t count)
00387    {
00388 #if defined(BOTAN_TARGET_CPU_HAS_KNOWN_ENDIANNESS)
00389    std::memcpy(out, in, sizeof(T)*count);
00390 
00391 #if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
00392    const size_t blocks = count - (count % 4);
00393    const size_t left = count - blocks;
00394 
00395    for(size_t i = 0; i != blocks; i += 4)
00396       bswap_4(out + i);
00397 
00398    for(size_t i = 0; i != left; ++i)
00399       out[blocks+i] = reverse_bytes(out[blocks+i]);
00400 #endif
00401 
00402 #else
00403    for(size_t i = 0; i != count; ++i)
00404       out[i] = load_be<T>(in, i);
00405 #endif
00406    }
00407 
00408 /**
00409 * Store a big-endian u16bit
00410 * @param in the input u16bit
00411 * @param out the byte array to write to
00412 */
00413 inline void store_be(u16bit in, byte out[2])
00414    {
00415 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00416    *reinterpret_cast<u16bit*>(out) = BOTAN_ENDIAN_B2N(in);
00417 #else
00418    out[0] = get_byte(0, in);
00419    out[1] = get_byte(1, in);
00420 #endif
00421    }
00422 
00423 /**
00424 * Store a little-endian u16bit
00425 * @param in the input u16bit
00426 * @param out the byte array to write to
00427 */
00428 inline void store_le(u16bit in, byte out[2])
00429    {
00430 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00431    *reinterpret_cast<u16bit*>(out) = BOTAN_ENDIAN_L2N(in);
00432 #else
00433    out[0] = get_byte(1, in);
00434    out[1] = get_byte(0, in);
00435 #endif
00436    }
00437 
00438 /**
00439 * Store a big-endian u32bit
00440 * @param in the input u32bit
00441 * @param out the byte array to write to
00442 */
00443 inline void store_be(u32bit in, byte out[4])
00444    {
00445 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00446    *reinterpret_cast<u32bit*>(out) = BOTAN_ENDIAN_B2N(in);
00447 #else
00448    out[0] = get_byte(0, in);
00449    out[1] = get_byte(1, in);
00450    out[2] = get_byte(2, in);
00451    out[3] = get_byte(3, in);
00452 #endif
00453    }
00454 
00455 /**
00456 * Store a little-endian u32bit
00457 * @param in the input u32bit
00458 * @param out the byte array to write to
00459 */
00460 inline void store_le(u32bit in, byte out[4])
00461    {
00462 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00463    *reinterpret_cast<u32bit*>(out) = BOTAN_ENDIAN_L2N(in);
00464 #else
00465    out[0] = get_byte(3, in);
00466    out[1] = get_byte(2, in);
00467    out[2] = get_byte(1, in);
00468    out[3] = get_byte(0, in);
00469 #endif
00470    }
00471 
00472 /**
00473 * Store a big-endian u64bit
00474 * @param in the input u64bit
00475 * @param out the byte array to write to
00476 */
00477 inline void store_be(u64bit in, byte out[8])
00478    {
00479 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00480    *reinterpret_cast<u64bit*>(out) = BOTAN_ENDIAN_B2N(in);
00481 #else
00482    out[0] = get_byte(0, in);
00483    out[1] = get_byte(1, in);
00484    out[2] = get_byte(2, in);
00485    out[3] = get_byte(3, in);
00486    out[4] = get_byte(4, in);
00487    out[5] = get_byte(5, in);
00488    out[6] = get_byte(6, in);
00489    out[7] = get_byte(7, in);
00490 #endif
00491    }
00492 
00493 /**
00494 * Store a little-endian u64bit
00495 * @param in the input u64bit
00496 * @param out the byte array to write to
00497 */
00498 inline void store_le(u64bit in, byte out[8])
00499    {
00500 #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK
00501    *reinterpret_cast<u64bit*>(out) = BOTAN_ENDIAN_L2N(in);
00502 #else
00503    out[0] = get_byte(7, in);
00504    out[1] = get_byte(6, in);
00505    out[2] = get_byte(5, in);
00506    out[3] = get_byte(4, in);
00507    out[4] = get_byte(3, in);
00508    out[5] = get_byte(2, in);
00509    out[6] = get_byte(1, in);
00510    out[7] = get_byte(0, in);
00511 #endif
00512    }
00513 
00514 /**
00515 * Store two little-endian words
00516 * @param out the output byte array
00517 * @param x0 the first word
00518 * @param x1 the second word
00519 */
00520 template<typename T>
00521 inline void store_le(byte out[], T x0, T x1)
00522    {
00523    store_le(x0, out + (0 * sizeof(T)));
00524    store_le(x1, out + (1 * sizeof(T)));
00525    }
00526 
00527 /**
00528 * Store two big-endian words
00529 * @param out the output byte array
00530 * @param x0 the first word
00531 * @param x1 the second word
00532 */
00533 template<typename T>
00534 inline void store_be(byte out[], T x0, T x1)
00535    {
00536    store_be(x0, out + (0 * sizeof(T)));
00537    store_be(x1, out + (1 * sizeof(T)));
00538    }
00539 
00540 /**
00541 * Store four little-endian words
00542 * @param out the output byte array
00543 * @param x0 the first word
00544 * @param x1 the second word
00545 * @param x2 the third word
00546 * @param x3 the fourth word
00547 */
00548 template<typename T>
00549 inline void store_le(byte out[], T x0, T x1, T x2, T x3)
00550    {
00551    store_le(x0, out + (0 * sizeof(T)));
00552    store_le(x1, out + (1 * sizeof(T)));
00553    store_le(x2, out + (2 * sizeof(T)));
00554    store_le(x3, out + (3 * sizeof(T)));
00555    }
00556 
00557 /**
00558 * Store four big-endian words
00559 * @param out the output byte array
00560 * @param x0 the first word
00561 * @param x1 the second word
00562 * @param x2 the third word
00563 * @param x3 the fourth word
00564 */
00565 template<typename T>
00566 inline void store_be(byte out[], T x0, T x1, T x2, T x3)
00567    {
00568    store_be(x0, out + (0 * sizeof(T)));
00569    store_be(x1, out + (1 * sizeof(T)));
00570    store_be(x2, out + (2 * sizeof(T)));
00571    store_be(x3, out + (3 * sizeof(T)));
00572    }
00573 
00574 /**
00575 * Store eight little-endian words
00576 * @param out the output byte array
00577 * @param x0 the first word
00578 * @param x1 the second word
00579 * @param x2 the third word
00580 * @param x3 the fourth word
00581 * @param x4 the fifth word
00582 * @param x5 the sixth word
00583 * @param x6 the seventh word
00584 * @param x7 the eighth word
00585 */
00586 template<typename T>
00587 inline void store_le(byte out[], T x0, T x1, T x2, T x3,
00588                                  T x4, T x5, T x6, T x7)
00589    {
00590    store_le(x0, out + (0 * sizeof(T)));
00591    store_le(x1, out + (1 * sizeof(T)));
00592    store_le(x2, out + (2 * sizeof(T)));
00593    store_le(x3, out + (3 * sizeof(T)));
00594    store_le(x4, out + (4 * sizeof(T)));
00595    store_le(x5, out + (5 * sizeof(T)));
00596    store_le(x6, out + (6 * sizeof(T)));
00597    store_le(x7, out + (7 * sizeof(T)));
00598    }
00599 
00600 /**
00601 * Store eight big-endian words
00602 * @param out the output byte array
00603 * @param x0 the first word
00604 * @param x1 the second word
00605 * @param x2 the third word
00606 * @param x3 the fourth word
00607 * @param x4 the fifth word
00608 * @param x5 the sixth word
00609 * @param x6 the seventh word
00610 * @param x7 the eighth word
00611 */
00612 template<typename T>
00613 inline void store_be(byte out[], T x0, T x1, T x2, T x3,
00614                                  T x4, T x5, T x6, T x7)
00615    {
00616    store_be(x0, out + (0 * sizeof(T)));
00617    store_be(x1, out + (1 * sizeof(T)));
00618    store_be(x2, out + (2 * sizeof(T)));
00619    store_be(x3, out + (3 * sizeof(T)));
00620    store_be(x4, out + (4 * sizeof(T)));
00621    store_be(x5, out + (5 * sizeof(T)));
00622    store_be(x6, out + (6 * sizeof(T)));
00623    store_be(x7, out + (7 * sizeof(T)));
00624    }
00625 
00626 template<typename T>
00627 void copy_out_be(byte out[], size_t out_bytes, const T in[])
00628    {
00629    while(out_bytes >= sizeof(T))
00630       {
00631       store_be(in[0], out);
00632       out += sizeof(T);
00633       out_bytes -= sizeof(T);
00634       in += 1;
00635    }
00636 
00637    for(size_t i = 0; i != out_bytes; ++i)
00638       out[i] = get_byte(i%8, in[0]);
00639    }
00640 
00641 template<typename T, typename Alloc>
00642 void copy_out_vec_be(byte out[], size_t out_bytes, const std::vector<T, Alloc>& in)
00643    {
00644    copy_out_be(out, out_bytes, &in[0]);
00645    }
00646 
00647 template<typename T>
00648 void copy_out_le(byte out[], size_t out_bytes, const T in[])
00649    {
00650    while(out_bytes >= sizeof(T))
00651       {
00652       store_le(in[0], out);
00653       out += sizeof(T);
00654       out_bytes -= sizeof(T);
00655       in += 1;
00656    }
00657 
00658    for(size_t i = 0; i != out_bytes; ++i)
00659       out[i] = get_byte(sizeof(T) - 1 - (i % 8), in[0]);
00660    }
00661 
00662 template<typename T, typename Alloc>
00663 void copy_out_vec_le(byte out[], size_t out_bytes, const std::vector<T, Alloc>& in)
00664    {
00665    copy_out_le(out, out_bytes, &in[0]);
00666    }
00667 
00668 }
00669 
00670 #endif