1 /*
2  * MIT License
3  *
4  * Copyright (c) 2023 Benign X
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  */
25 
26 #include "library.h"
27 
RANDOM_CALL_PROCESS(void)28 __attribute__((weak)) uint32_t RANDOM_CALL_PROCESS(void)
29 {
30     /*Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs"*/
31     static uint32_t x = 0x114514;
32     x ^= x << 13;
33     x ^= x >> 17;
34     x ^= x << 5;
35 
36     return x;
37 }
38 
39 const uint32_t ALPHANUM_AND_CJK_TABLE[] = {
40     0x4e00, 0x9fa5, // CJK Unified Ideographs
41     'A', 'Z',
42     'a', 'z',
43     '0', '9',
44 };
45 const uint32_t ALPHANUM_AND_CJK_TABLE_LEN = sizeof(ALPHANUM_AND_CJK_TABLE) / sizeof(unicode_t) / 2;
46 
47 const uint32_t ONLY_CJK_TABLE[] = {
48     0x4e00, 0x9fa5, // CJK Unified Ideographs
49 };
50 const uint32_t ONLY_CJK_TABLE_LEN = sizeof(ALPHANUM_AND_CJK_TABLE) / sizeof(unicode_t) / 2;
51 
52 const uint32_t ALPHANUM_TABLE[] = {
53     'A', 'Z',
54     'a', 'z',
55     '0', '9',
56 };
57 const uint32_t ALPHANUM_TABLE_LEN = sizeof(ALPHANUM_TABLE) / sizeof(unicode_t) / 2;
58 
unicode_to_utf8_bytes_len(unicode_t unicode)59 static int unicode_to_utf8_bytes_len(unicode_t unicode)
60 {
61     if(unicode < 0x80) {
62         return 1;
63     }
64     else if(unicode < 0x800) {
65         return 2;
66     }
67     else if(unicode < 0x10000) {
68         return 3;
69     }
70     else if(unicode < 0x200000) {
71         return 4;
72     }
73     else if(unicode < 0x4000000) {
74         return 5;
75     }
76     else {
77         return 6;
78     }
79 }
80 
unicode_to_uft8(utf8_t * buf,uint32_t buf_len,unicode_t unicode)81 static int unicode_to_uft8(utf8_t * buf, uint32_t buf_len, unicode_t unicode)
82 {
83     uint32_t unicode_len = unicode_to_utf8_bytes_len(unicode);
84     if(buf_len < unicode_len) {
85         return -1;
86     }
87 
88     int buf_index = 0;
89 
90     switch(unicode_len) {
91         case 1:
92             buf[buf_index++] = (uint8_t) unicode;
93             break;
94         case 2:
95             buf[buf_index++] = (uint8_t)(0xc0 | (unicode >> 6));
96             buf[buf_index++] = (uint8_t)(0x80 | (unicode & 0x3f));
97             break;
98         case 3:
99             buf[buf_index++] = (uint8_t)(0xe0 | (unicode >> 12));
100             buf[buf_index++] = (uint8_t)(0x80 | ((unicode >> 6) & 0x3f));
101             buf[buf_index++] = (uint8_t)(0x80 | (unicode & 0x3f));
102             break;
103         case 4:
104             buf[buf_index++] = (uint8_t)(0xf0 | (unicode >> 18));
105             buf[buf_index++] = (uint8_t)(0x80 | ((unicode >> 12) & 0x3f));
106             buf[buf_index++] = (uint8_t)(0x80 | ((unicode >> 6) & 0x3f));
107             buf[buf_index++] = (uint8_t)(0x80 | (unicode & 0x3f));
108             break;
109         case 5:
110             buf[buf_index++] = (uint8_t)(0xf8 | (unicode >> 24));
111             buf[buf_index++] = (uint8_t)(0x80 | ((unicode >> 18) & 0x3f));
112             buf[buf_index++] = (uint8_t)(0x80 | ((unicode >> 12) & 0x3f));
113             buf[buf_index++] = (uint8_t)(0x80 | ((unicode >> 6) & 0x3f));
114             buf[buf_index++] = (uint8_t)(0x80 | (unicode & 0x3f));
115             break;
116         case 6:
117             buf[buf_index++] = (uint8_t)(0xfc | (unicode >> 30));
118             buf[buf_index++] = (uint8_t)(0x80 | ((unicode >> 24) & 0x3f));
119             buf[buf_index++] = (uint8_t)(0x80 | ((unicode >> 18) & 0x3f));
120             buf[buf_index++] = (uint8_t)(0x80 | ((unicode >> 12) & 0x3f));
121             buf[buf_index++] = (uint8_t)(0x80 | ((unicode >> 6) & 0x3f));
122             buf[buf_index++] = (uint8_t)(0x80 | (unicode & 0x3f));
123             break;
124         default:
125             return -1;
126     }
127     return buf_index;
128 }
129 
random_one_utf8_char(utf8_t * buf,int buf_len,unicode_t char_range_min,unicode_t char_range_max)130 static int random_one_utf8_char(utf8_t * buf, int buf_len, unicode_t char_range_min, unicode_t char_range_max)
131 {
132     if(buf_len < 1) {
133         return -1;
134     }
135 
136     uint32_t r = RANDOM_CALL_PROCESS() % (char_range_max - char_range_min + 1) + char_range_min;
137 
138     return unicode_to_uft8(buf, buf_len, r);
139 }
140 
random_utf8_chars(utf8_t * buf,int buf_len,const unicode_t * ranges,uint32_t range_num,int char_num)141 int random_utf8_chars(utf8_t * buf, int buf_len, const unicode_t * ranges, uint32_t range_num, int char_num)
142 {
143     if(buf_len < char_num) {
144         return -1;
145     }
146 
147     int buf_index = 0;
148     for(int i = 0; i < char_num && buf_index < buf_len; i++) {
149         int range_index = RANDOM_CALL_PROCESS() % range_num;
150         int ret = random_one_utf8_char(buf + buf_index,
151                                        buf_len - buf_index,
152                                        ranges[2 * range_index],
153                                        ranges[2 * range_index + 1]);
154         if(ret < 0) {
155             return -1;
156         }
157         buf_index += ret;
158     }
159 
160     buf[buf_index] = '\0';
161     return buf_index;
162 }
163