1 | #include "mupdf/fitz.h" |
2 | |
3 | /* The pseudo-random number generator in this file is based on the MIT licensed |
4 | * implementation in musl libc. */ |
5 | |
6 | #include <string.h> |
7 | |
8 | /* The seed is initialized in context.c as follows: |
9 | * static uint16_t __seed48[7] = { 0, 0, 0, 0xe66d, 0xdeec, 0x5, 0xb }; |
10 | */ |
11 | |
12 | static uint64_t fz_rand48_step(uint16_t *xi, uint16_t *lc) |
13 | { |
14 | uint64_t a, x; |
15 | x = xi[0] | (xi[1]+0U)<<16 | (xi[2]+0ULL)<<32; |
16 | a = lc[0] | (lc[1]+0U)<<16 | (lc[2]+0ULL)<<32; |
17 | x = a*x + lc[3]; |
18 | xi[0] = x; |
19 | xi[1] = x>>16; |
20 | xi[2] = x>>32; |
21 | return x & 0xffffffffffffull; |
22 | } |
23 | |
24 | double fz_erand48(fz_context *ctx, uint16_t s[3]) |
25 | { |
26 | union { |
27 | uint64_t u; |
28 | double f; |
29 | } x = { 0x3ff0000000000000ULL | fz_rand48_step(s, ctx->seed48+3)<<4 }; |
30 | return x.f - 1.0; |
31 | } |
32 | |
33 | /* |
34 | Pseudo-random numbers using a linear congruential algorithm and 48-bit |
35 | integer arithmetic. |
36 | */ |
37 | double fz_drand48(fz_context *ctx) |
38 | { |
39 | return fz_erand48(ctx, ctx->seed48); |
40 | } |
41 | |
42 | int32_t fz_nrand48(fz_context *ctx, uint16_t s[3]) |
43 | { |
44 | return fz_rand48_step(s, ctx->seed48+3) >> 17; |
45 | } |
46 | |
47 | int32_t fz_lrand48(fz_context *ctx) |
48 | { |
49 | return fz_nrand48(ctx, ctx->seed48); |
50 | } |
51 | |
52 | int32_t fz_jrand48(fz_context *ctx, uint16_t s[3]) |
53 | { |
54 | return (int32_t)(fz_rand48_step(s, ctx->seed48+3) >> 16); |
55 | } |
56 | |
57 | int32_t fz_mrand48(fz_context *ctx) |
58 | { |
59 | return fz_jrand48(ctx, ctx->seed48); |
60 | } |
61 | |
62 | void fz_lcong48(fz_context *ctx, uint16_t p[7]) |
63 | { |
64 | memcpy(ctx->seed48, p, sizeof ctx->seed48); |
65 | } |
66 | |
67 | uint16_t *fz_seed48(fz_context *ctx, uint16_t *s) |
68 | { |
69 | static uint16_t p[3]; |
70 | memcpy(p, ctx->seed48, sizeof p); |
71 | memcpy(ctx->seed48, s, sizeof p); |
72 | return p; |
73 | } |
74 | |
75 | void fz_srand48(fz_context *ctx, int32_t seed) |
76 | { |
77 | uint16_t p[3] = { 0x330e, seed, seed>>16 }; |
78 | fz_seed48(ctx, p); |
79 | } |
80 | |
81 | /* |
82 | Fill block with len bytes of pseudo-randomness. |
83 | */ |
84 | void fz_memrnd(fz_context *ctx, unsigned char *data, int len) |
85 | { |
86 | while (len-- > 0) |
87 | *data++ = (unsigned char)fz_lrand48(ctx); |
88 | } |
89 | |