LCOV - code coverage report
Current view: top level - libreoffice/sal/rtl/source - random.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 90 96 93.8 %
Date: 2012-12-17 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <sal/types.h>
      21             : #include <osl/thread.h>
      22             : #include <osl/time.h>
      23             : #include <rtl/alloc.h>
      24             : #include <rtl/digest.h>
      25             : #include <rtl/random.h>
      26             : 
      27             : /*========================================================================
      28             :  *
      29             :  * rtlRandom internals.
      30             :  *
      31             :  *======================================================================*/
      32             : #define RTL_RANDOM_RNG_1(a) ((a) * 16807L)
      33             : #define RTL_RANDOM_RNG_2(a) ((a) * 65539L)
      34             : 
      35             : #define RTL_RANDOM_RNG(x, y, z) \
      36             : { \
      37             :     (x) = 170 * ((x) % 178) - 63 * ((x) / 178); \
      38             :     if ((x) < 0) (x) += 30328L; \
      39             :     \
      40             :     (y) = 171 * ((y) % 177) -  2 * ((y) / 177); \
      41             :     if ((y) < 0) (y) += 30269L; \
      42             :     \
      43             :     (z) = 172 * ((z) % 176) - 35 * ((z) / 176); \
      44             :     if ((z) < 0) (z) += 30307L; \
      45             : }
      46             : 
      47             : /** RandomData_Impl.
      48             :  */
      49             : struct RandomData_Impl
      50             : {
      51             :     sal_Int16 m_nX;
      52             :     sal_Int16 m_nY;
      53             :     sal_Int16 m_nZ;
      54             : };
      55             : 
      56             : /** __rtl_random_data.
      57             :  */
      58             : static double __rtl_random_data (RandomData_Impl *pImpl);
      59             : 
      60             : /** RandomPool_Impl.
      61             :  */
      62             : #define RTL_RANDOM_DIGEST      rtl_Digest_AlgorithmMD5
      63             : #define RTL_RANDOM_SIZE_DIGEST RTL_DIGEST_LENGTH_MD5
      64             : #define RTL_RANDOM_SIZE_POOL   1023
      65             : 
      66             : struct RandomPool_Impl
      67             : {
      68             :     rtlDigest  m_hDigest;
      69             :     sal_uInt8  m_pDigest[RTL_RANDOM_SIZE_DIGEST];
      70             :     sal_uInt8  m_pData[RTL_RANDOM_SIZE_POOL + 1];
      71             :     sal_uInt32 m_nData;
      72             :     sal_uInt32 m_nIndex;
      73             :     sal_uInt32 m_nCount;
      74             : };
      75             : 
      76             : /** __rtl_random_initPool.
      77             :  */
      78             : static sal_Bool __rtl_random_initPool (
      79             :     RandomPool_Impl *pImpl);
      80             : 
      81             : /** __rtl_random_seedPool.
      82             :  */
      83             : static void __rtl_random_seedPool (
      84             :     RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen);
      85             : 
      86             : /** __rtl_random_readPool.
      87             :  */
      88             : static void __rtl_random_readPool (
      89             :     RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen);
      90             : 
      91             : /*
      92             :  * __rtl_random_data.
      93             :  */
      94       33012 : static double __rtl_random_data (RandomData_Impl *pImpl)
      95             : {
      96             :     double random;
      97             : 
      98       33012 :     RTL_RANDOM_RNG (pImpl->m_nX, pImpl->m_nY, pImpl->m_nZ);
      99             :     random = (((double)(pImpl->m_nX) / 30328.0) +
     100             :               ((double)(pImpl->m_nY) / 30269.0) +
     101       33012 :               ((double)(pImpl->m_nZ) / 30307.0)   );
     102             : 
     103       33012 :     random -= ((double)((sal_uInt32)(random)));
     104       33012 :     return (random);
     105             : }
     106             : 
     107             : /*
     108             :  * __rtl_random_initPool.
     109             :  */
     110         262 : static sal_Bool __rtl_random_initPool (RandomPool_Impl *pImpl)
     111             : {
     112         262 :     pImpl->m_hDigest = rtl_digest_create (RTL_RANDOM_DIGEST);
     113         262 :     if (pImpl->m_hDigest)
     114             :     {
     115             :         oslThreadIdentifier id;
     116             :         TimeValue           tv;
     117             :         RandomData_Impl     rd;
     118             :         double              seed;
     119             : 
     120             :         /* The use of uninitialized stack variables as a way to
     121             :          * enhance the entropy of the random pool triggers
     122             :          * memory checkers like purify and valgrind.
     123             :          */
     124             : 
     125             :         /*
     126             :         __rtl_random_seedPool (pImpl, (sal_uInt8*)&id, sizeof(id));
     127             :         __rtl_random_seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
     128             :         __rtl_random_seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
     129             :         */
     130             : 
     131         262 :         id = osl_getThreadIdentifier (NULL);
     132         262 :         id = RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(id));
     133         262 :         __rtl_random_seedPool (pImpl, (sal_uInt8*)&id, sizeof(id));
     134             : 
     135         262 :         osl_getSystemTime (&tv);
     136         262 :         tv.Seconds = RTL_RANDOM_RNG_2(tv.Seconds);
     137         262 :         tv.Nanosec = RTL_RANDOM_RNG_2(tv.Nanosec);
     138         262 :         __rtl_random_seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
     139             : 
     140         262 :         rd.m_nX = (sal_Int16)(((id         >> 1) << 1) + 1);
     141         262 :         rd.m_nY = (sal_Int16)(((tv.Seconds >> 1) << 1) + 1);
     142         262 :         rd.m_nZ = (sal_Int16)(((tv.Nanosec >> 1) << 1) + 1);
     143         262 :         __rtl_random_seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
     144             : 
     145       33536 :         while (pImpl->m_nData < RTL_RANDOM_SIZE_POOL)
     146             :         {
     147       33012 :             seed = __rtl_random_data (&rd);
     148       33012 :             __rtl_random_seedPool (pImpl, (sal_uInt8*)&seed, sizeof(seed));
     149             :         }
     150         262 :         return sal_True;
     151             :     }
     152           0 :     return sal_False;
     153             : }
     154             : 
     155             : /*
     156             :  * __rtl_random_seedPool.
     157             :  */
     158       33876 : static void __rtl_random_seedPool (
     159             :     RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen)
     160             : {
     161             :     sal_Size i;
     162             :     sal_sSize  j, k;
     163             : 
     164       67752 :     for (i = 0; i < nBufLen; i += RTL_RANDOM_SIZE_DIGEST)
     165             :     {
     166       33876 :         j = nBufLen - i;
     167       33876 :         if (j > RTL_RANDOM_SIZE_DIGEST)
     168           0 :             j = RTL_RANDOM_SIZE_DIGEST;
     169             : 
     170             :         rtl_digest_update (
     171       33876 :             pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
     172             : 
     173       33876 :         k = (pImpl->m_nIndex + j) - RTL_RANDOM_SIZE_POOL;
     174       33876 :         if (k > 0)
     175             :         {
     176             :             rtl_digest_update (
     177         262 :                 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k);
     178             :             rtl_digest_update (
     179         262 :                 pImpl->m_hDigest, &(pImpl->m_pData[0]), k);
     180             :         }
     181             :         else
     182             :         {
     183             :             rtl_digest_update (
     184       33614 :                 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j);
     185             :         }
     186             : 
     187       33876 :         rtl_digest_update (pImpl->m_hDigest, pBuffer, j);
     188       33876 :         pBuffer += j;
     189             : 
     190             :         rtl_digest_get (
     191       33876 :             pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
     192      303312 :         for (k = 0; k < j; k++)
     193             :         {
     194      269436 :             pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k];
     195      269436 :             if (pImpl->m_nIndex >= RTL_RANDOM_SIZE_POOL)
     196             :             {
     197         262 :                 pImpl->m_nData  = RTL_RANDOM_SIZE_POOL;
     198         262 :                 pImpl->m_nIndex = 0;
     199             :             }
     200             :         }
     201             :     }
     202             : 
     203       33876 :     if (pImpl->m_nIndex > pImpl->m_nData)
     204       33536 :         pImpl->m_nData = pImpl->m_nIndex;
     205       33876 : }
     206             : 
     207             : /*
     208             :  * __rtl_random_readPool.
     209             :  */
     210        4333 : static void __rtl_random_readPool (
     211             :     RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen)
     212             : {
     213             :     sal_Int32 j, k;
     214             : 
     215       15438 :     while (nBufLen > 0)
     216             :     {
     217        6772 :         j = nBufLen;
     218        6772 :         if (j > RTL_RANDOM_SIZE_DIGEST/2)
     219        2439 :             j = RTL_RANDOM_SIZE_DIGEST/2;
     220        6772 :         nBufLen -= j;
     221             : 
     222             :         rtl_digest_update (
     223             :             pImpl->m_hDigest,
     224             :             &(pImpl->m_pDigest[RTL_RANDOM_SIZE_DIGEST/2]),
     225        6772 :             RTL_RANDOM_SIZE_DIGEST/2);
     226             : 
     227        6772 :         k = (pImpl->m_nIndex + j) - pImpl->m_nData;
     228        6772 :         if (k > 0)
     229             :         {
     230             :             rtl_digest_update (
     231          15 :                 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k);
     232             :             rtl_digest_update (
     233          15 :                 pImpl->m_hDigest, &(pImpl->m_pData[0]), k);
     234             :         }
     235             :         else
     236             :         {
     237             :             rtl_digest_update (
     238        6757 :                 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j);
     239             :         }
     240             : 
     241             :         rtl_digest_get (
     242        6772 :             pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
     243       58380 :         for (k = 0; k < j; k++)
     244             :         {
     245       51608 :             if (pImpl->m_nIndex >= pImpl->m_nData) pImpl->m_nIndex = 0;
     246       51608 :             pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k];
     247       51608 :             *pBuffer++ = pImpl->m_pDigest[k + RTL_RANDOM_SIZE_DIGEST/2];
     248             :         }
     249             :     }
     250             : 
     251        4333 :     pImpl->m_nCount++;
     252             :     rtl_digest_update (
     253        4333 :         pImpl->m_hDigest, &(pImpl->m_nCount), sizeof(pImpl->m_nCount));
     254             :     rtl_digest_update (
     255        4333 :         pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
     256             :     rtl_digest_get (
     257        4333 :         pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
     258        4333 : }
     259             : 
     260             : /*========================================================================
     261             :  *
     262             :  * rtlRandom implementation.
     263             :  *
     264             :  *======================================================================*/
     265             : /*
     266             :  * rtl_random_createPool.
     267             :  */
     268         262 : rtlRandomPool SAL_CALL rtl_random_createPool() SAL_THROW_EXTERN_C()
     269             : {
     270         262 :     RandomPool_Impl *pImpl = (RandomPool_Impl*)NULL;
     271         262 :     pImpl = (RandomPool_Impl*)rtl_allocateZeroMemory (sizeof(RandomPool_Impl));
     272         262 :     if (pImpl)
     273             :     {
     274         262 :         if (!__rtl_random_initPool (pImpl))
     275             :         {
     276           0 :             rtl_freeZeroMemory (pImpl, sizeof(RandomPool_Impl));
     277           0 :             pImpl = (RandomPool_Impl*)NULL;
     278             :         }
     279             :     }
     280         262 :     return ((rtlRandomPool)pImpl);
     281             : }
     282             : 
     283             : /*
     284             :  * rtl_random_destroyPool.
     285             :  */
     286          94 : void SAL_CALL rtl_random_destroyPool (rtlRandomPool Pool) SAL_THROW_EXTERN_C()
     287             : {
     288          94 :     RandomPool_Impl *pImpl = (RandomPool_Impl *)Pool;
     289          94 :     if (pImpl)
     290             :     {
     291          94 :         rtl_digest_destroy (pImpl->m_hDigest);
     292          94 :         rtl_freeZeroMemory (pImpl, sizeof (RandomPool_Impl));
     293             :     }
     294          94 : }
     295             : 
     296             : /*
     297             :  * rtl_random_addBytes.
     298             :  */
     299          78 : rtlRandomError SAL_CALL rtl_random_addBytes (
     300             :     rtlRandomPool Pool, const void *Buffer, sal_Size Bytes) SAL_THROW_EXTERN_C()
     301             : {
     302          78 :     RandomPool_Impl *pImpl   = (RandomPool_Impl *)Pool;
     303          78 :     const sal_uInt8 *pBuffer = (const sal_uInt8 *)Buffer;
     304             : 
     305          78 :     if ((pImpl == NULL) || (pBuffer == NULL))
     306           0 :         return rtl_Random_E_Argument;
     307             : 
     308          78 :     __rtl_random_seedPool (pImpl, pBuffer, Bytes);
     309          78 :     return rtl_Random_E_None;
     310             : }
     311             : 
     312             : /*
     313             :  * rtl_random_getBytes.
     314             :  */
     315        4333 : rtlRandomError SAL_CALL rtl_random_getBytes (
     316             :     rtlRandomPool Pool, void *Buffer, sal_Size Bytes) SAL_THROW_EXTERN_C()
     317             : {
     318        4333 :     RandomPool_Impl *pImpl   = (RandomPool_Impl *)Pool;
     319        4333 :     sal_uInt8       *pBuffer = (sal_uInt8 *)Buffer;
     320             : 
     321        4333 :     if ((pImpl == NULL) || (pBuffer == NULL))
     322           0 :         return rtl_Random_E_Argument;
     323             : 
     324        4333 :     __rtl_random_readPool (pImpl, pBuffer, Bytes);
     325        4333 :     return rtl_Random_E_None;
     326             : }
     327             : 
     328             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10