Bump version to 4.1-6
[LibreOffice.git] / sal / rtl / random.cxx
blob87c5bfc42e30ceb0dac3ec097d99e433607388b7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
27 /*========================================================================
29 * rtlRandom internals.
31 *======================================================================*/
32 #define RTL_RANDOM_RNG_1(a) ((a) * 16807L)
33 #define RTL_RANDOM_RNG_2(a) ((a) * 65539L)
35 #define RTL_RANDOM_RNG(x, y, z) \
36 { \
37 (x) = 170 * ((x) % 178) - 63 * ((x) / 178); \
38 if ((x) < 0) (x) += 30328L; \
40 (y) = 171 * ((y) % 177) - 2 * ((y) / 177); \
41 if ((y) < 0) (y) += 30269L; \
43 (z) = 172 * ((z) % 176) - 35 * ((z) / 176); \
44 if ((z) < 0) (z) += 30307L; \
47 /** RandomData_Impl.
49 struct RandomData_Impl
51 sal_Int16 m_nX;
52 sal_Int16 m_nY;
53 sal_Int16 m_nZ;
56 /** __rtl_random_data.
58 static double __rtl_random_data (RandomData_Impl *pImpl);
60 /** RandomPool_Impl.
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
66 struct RandomPool_Impl
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;
76 /** __rtl_random_initPool.
78 static sal_Bool __rtl_random_initPool (
79 RandomPool_Impl *pImpl);
81 /** __rtl_random_seedPool.
83 static void __rtl_random_seedPool (
84 RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen);
86 /** __rtl_random_readPool.
88 static void __rtl_random_readPool (
89 RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen);
92 * __rtl_random_data.
94 static double __rtl_random_data (RandomData_Impl *pImpl)
96 double random;
98 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 ((double)(pImpl->m_nZ) / 30307.0) );
103 random -= ((double)((sal_uInt32)(random)));
104 return (random);
108 * __rtl_random_initPool.
110 static sal_Bool __rtl_random_initPool (RandomPool_Impl *pImpl)
112 pImpl->m_hDigest = rtl_digest_create (RTL_RANDOM_DIGEST);
113 if (pImpl->m_hDigest)
115 oslThreadIdentifier id;
116 TimeValue tv;
117 RandomData_Impl rd;
118 double seed;
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.
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));
131 id = osl_getThreadIdentifier (NULL);
132 id = RTL_RANDOM_RNG_2(RTL_RANDOM_RNG_1(id));
133 __rtl_random_seedPool (pImpl, (sal_uInt8*)&id, sizeof(id));
135 osl_getSystemTime (&tv);
136 tv.Seconds = RTL_RANDOM_RNG_2(tv.Seconds);
137 tv.Nanosec = RTL_RANDOM_RNG_2(tv.Nanosec);
138 __rtl_random_seedPool (pImpl, (sal_uInt8*)&tv, sizeof(tv));
140 rd.m_nX = (sal_Int16)(((id >> 1) << 1) + 1);
141 rd.m_nY = (sal_Int16)(((tv.Seconds >> 1) << 1) + 1);
142 rd.m_nZ = (sal_Int16)(((tv.Nanosec >> 1) << 1) + 1);
143 __rtl_random_seedPool (pImpl, (sal_uInt8*)&rd, sizeof(rd));
145 while (pImpl->m_nData < RTL_RANDOM_SIZE_POOL)
147 seed = __rtl_random_data (&rd);
148 __rtl_random_seedPool (pImpl, (sal_uInt8*)&seed, sizeof(seed));
150 return sal_True;
152 return sal_False;
156 * __rtl_random_seedPool.
158 static void __rtl_random_seedPool (
159 RandomPool_Impl *pImpl, const sal_uInt8 *pBuffer, sal_Size nBufLen)
161 sal_Size i;
162 sal_sSize j, k;
164 for (i = 0; i < nBufLen; i += RTL_RANDOM_SIZE_DIGEST)
166 j = nBufLen - i;
167 if (j > RTL_RANDOM_SIZE_DIGEST)
168 j = RTL_RANDOM_SIZE_DIGEST;
170 rtl_digest_update (
171 pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
173 k = (pImpl->m_nIndex + j) - RTL_RANDOM_SIZE_POOL;
174 if (k > 0)
176 rtl_digest_update (
177 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k);
178 rtl_digest_update (
179 pImpl->m_hDigest, &(pImpl->m_pData[0]), k);
181 else
183 rtl_digest_update (
184 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j);
187 rtl_digest_update (pImpl->m_hDigest, pBuffer, j);
188 pBuffer += j;
190 rtl_digest_get (
191 pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
192 for (k = 0; k < j; k++)
194 pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k];
195 if (pImpl->m_nIndex >= RTL_RANDOM_SIZE_POOL)
197 pImpl->m_nData = RTL_RANDOM_SIZE_POOL;
198 pImpl->m_nIndex = 0;
203 if (pImpl->m_nIndex > pImpl->m_nData)
204 pImpl->m_nData = pImpl->m_nIndex;
208 * __rtl_random_readPool.
210 static void __rtl_random_readPool (
211 RandomPool_Impl *pImpl, sal_uInt8 *pBuffer, sal_Size nBufLen)
213 sal_Int32 j, k;
215 while (nBufLen > 0)
217 j = nBufLen;
218 if (j > RTL_RANDOM_SIZE_DIGEST/2)
219 j = RTL_RANDOM_SIZE_DIGEST/2;
220 nBufLen -= j;
222 rtl_digest_update (
223 pImpl->m_hDigest,
224 &(pImpl->m_pDigest[RTL_RANDOM_SIZE_DIGEST/2]),
225 RTL_RANDOM_SIZE_DIGEST/2);
227 k = (pImpl->m_nIndex + j) - pImpl->m_nData;
228 if (k > 0)
230 rtl_digest_update (
231 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j - k);
232 rtl_digest_update (
233 pImpl->m_hDigest, &(pImpl->m_pData[0]), k);
235 else
237 rtl_digest_update (
238 pImpl->m_hDigest, &(pImpl->m_pData[pImpl->m_nIndex]), j);
241 rtl_digest_get (
242 pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
243 for (k = 0; k < j; k++)
245 if (pImpl->m_nIndex >= pImpl->m_nData) pImpl->m_nIndex = 0;
246 pImpl->m_pData[pImpl->m_nIndex++] ^= pImpl->m_pDigest[k];
247 *pBuffer++ = pImpl->m_pDigest[k + RTL_RANDOM_SIZE_DIGEST/2];
251 pImpl->m_nCount++;
252 rtl_digest_update (
253 pImpl->m_hDigest, &(pImpl->m_nCount), sizeof(pImpl->m_nCount));
254 rtl_digest_update (
255 pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
256 rtl_digest_get (
257 pImpl->m_hDigest, pImpl->m_pDigest, RTL_RANDOM_SIZE_DIGEST);
260 /*========================================================================
262 * rtlRandom implementation.
264 *======================================================================*/
266 * rtl_random_createPool.
268 rtlRandomPool SAL_CALL rtl_random_createPool() SAL_THROW_EXTERN_C()
270 RandomPool_Impl *pImpl = (RandomPool_Impl*)NULL;
271 pImpl = (RandomPool_Impl*)rtl_allocateZeroMemory (sizeof(RandomPool_Impl));
272 if (pImpl)
274 if (!__rtl_random_initPool (pImpl))
276 rtl_freeZeroMemory (pImpl, sizeof(RandomPool_Impl));
277 pImpl = (RandomPool_Impl*)NULL;
280 return ((rtlRandomPool)pImpl);
284 * rtl_random_destroyPool.
286 void SAL_CALL rtl_random_destroyPool (rtlRandomPool Pool) SAL_THROW_EXTERN_C()
288 RandomPool_Impl *pImpl = (RandomPool_Impl *)Pool;
289 if (pImpl)
291 rtl_digest_destroy (pImpl->m_hDigest);
292 rtl_freeZeroMemory (pImpl, sizeof (RandomPool_Impl));
297 * rtl_random_addBytes.
299 rtlRandomError SAL_CALL rtl_random_addBytes (
300 rtlRandomPool Pool, const void *Buffer, sal_Size Bytes) SAL_THROW_EXTERN_C()
302 RandomPool_Impl *pImpl = (RandomPool_Impl *)Pool;
303 const sal_uInt8 *pBuffer = (const sal_uInt8 *)Buffer;
305 if ((pImpl == NULL) || (pBuffer == NULL))
306 return rtl_Random_E_Argument;
308 __rtl_random_seedPool (pImpl, pBuffer, Bytes);
309 return rtl_Random_E_None;
313 * rtl_random_getBytes.
315 rtlRandomError SAL_CALL rtl_random_getBytes (
316 rtlRandomPool Pool, void *Buffer, sal_Size Bytes) SAL_THROW_EXTERN_C()
318 RandomPool_Impl *pImpl = (RandomPool_Impl *)Pool;
319 sal_uInt8 *pBuffer = (sal_uInt8 *)Buffer;
321 if ((pImpl == NULL) || (pBuffer == NULL))
322 return rtl_Random_E_Argument;
324 __rtl_random_readPool (pImpl, pBuffer, Bytes);
325 return rtl_Random_E_None;
328 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */