xref: /aosp_15_r20/external/grpc-grpc/third_party/utf8_range/main.c (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker #include <stdio.h>
2*cc02d7e2SAndroid Build Coastguard Worker #include <stdlib.h>
3*cc02d7e2SAndroid Build Coastguard Worker #include <string.h>
4*cc02d7e2SAndroid Build Coastguard Worker #include <inttypes.h>
5*cc02d7e2SAndroid Build Coastguard Worker #include <sys/types.h>
6*cc02d7e2SAndroid Build Coastguard Worker #include <sys/stat.h>
7*cc02d7e2SAndroid Build Coastguard Worker #include <sys/time.h>
8*cc02d7e2SAndroid Build Coastguard Worker #include <fcntl.h>
9*cc02d7e2SAndroid Build Coastguard Worker #include <unistd.h>
10*cc02d7e2SAndroid Build Coastguard Worker 
11*cc02d7e2SAndroid Build Coastguard Worker int utf8_naive(const unsigned char *data, int len);
12*cc02d7e2SAndroid Build Coastguard Worker int utf8_lookup(const unsigned char *data, int len);
13*cc02d7e2SAndroid Build Coastguard Worker int utf8_boost(const unsigned char *data, int len);
14*cc02d7e2SAndroid Build Coastguard Worker int utf8_lemire(const unsigned char *data, int len);
15*cc02d7e2SAndroid Build Coastguard Worker int utf8_range(const unsigned char *data, int len);
16*cc02d7e2SAndroid Build Coastguard Worker int utf8_range2(const unsigned char *data, int len);
17*cc02d7e2SAndroid Build Coastguard Worker #ifdef __AVX2__
18*cc02d7e2SAndroid Build Coastguard Worker int utf8_lemire_avx2(const unsigned char *data, int len);
19*cc02d7e2SAndroid Build Coastguard Worker int utf8_range_avx2(const unsigned char *data, int len);
20*cc02d7e2SAndroid Build Coastguard Worker #endif
21*cc02d7e2SAndroid Build Coastguard Worker 
22*cc02d7e2SAndroid Build Coastguard Worker static struct ftab {
23*cc02d7e2SAndroid Build Coastguard Worker     const char *name;
24*cc02d7e2SAndroid Build Coastguard Worker     int (*func)(const unsigned char *data, int len);
25*cc02d7e2SAndroid Build Coastguard Worker } ftab[] = {
26*cc02d7e2SAndroid Build Coastguard Worker     {
27*cc02d7e2SAndroid Build Coastguard Worker         .name = "naive",
28*cc02d7e2SAndroid Build Coastguard Worker         .func = utf8_naive,
29*cc02d7e2SAndroid Build Coastguard Worker     },
30*cc02d7e2SAndroid Build Coastguard Worker     {
31*cc02d7e2SAndroid Build Coastguard Worker         .name = "lookup",
32*cc02d7e2SAndroid Build Coastguard Worker         .func = utf8_lookup,
33*cc02d7e2SAndroid Build Coastguard Worker     },
34*cc02d7e2SAndroid Build Coastguard Worker     {
35*cc02d7e2SAndroid Build Coastguard Worker         .name = "lemire",
36*cc02d7e2SAndroid Build Coastguard Worker         .func = utf8_lemire,
37*cc02d7e2SAndroid Build Coastguard Worker     },
38*cc02d7e2SAndroid Build Coastguard Worker     {
39*cc02d7e2SAndroid Build Coastguard Worker         .name = "range",
40*cc02d7e2SAndroid Build Coastguard Worker         .func = utf8_range,
41*cc02d7e2SAndroid Build Coastguard Worker     },
42*cc02d7e2SAndroid Build Coastguard Worker     {
43*cc02d7e2SAndroid Build Coastguard Worker         .name = "range2",
44*cc02d7e2SAndroid Build Coastguard Worker         .func = utf8_range2,
45*cc02d7e2SAndroid Build Coastguard Worker     },
46*cc02d7e2SAndroid Build Coastguard Worker #ifdef __AVX2__
47*cc02d7e2SAndroid Build Coastguard Worker     {
48*cc02d7e2SAndroid Build Coastguard Worker         .name = "lemire_avx2",
49*cc02d7e2SAndroid Build Coastguard Worker         .func = utf8_lemire_avx2,
50*cc02d7e2SAndroid Build Coastguard Worker     },
51*cc02d7e2SAndroid Build Coastguard Worker     {
52*cc02d7e2SAndroid Build Coastguard Worker         .name = "range_avx2",
53*cc02d7e2SAndroid Build Coastguard Worker         .func = utf8_range_avx2,
54*cc02d7e2SAndroid Build Coastguard Worker     },
55*cc02d7e2SAndroid Build Coastguard Worker #endif
56*cc02d7e2SAndroid Build Coastguard Worker #ifdef BOOST
57*cc02d7e2SAndroid Build Coastguard Worker     {
58*cc02d7e2SAndroid Build Coastguard Worker         .name = "boost",
59*cc02d7e2SAndroid Build Coastguard Worker         .func = utf8_boost,
60*cc02d7e2SAndroid Build Coastguard Worker     },
61*cc02d7e2SAndroid Build Coastguard Worker #endif
62*cc02d7e2SAndroid Build Coastguard Worker };
63*cc02d7e2SAndroid Build Coastguard Worker 
load_test_buf(int len)64*cc02d7e2SAndroid Build Coastguard Worker static unsigned char *load_test_buf(int len)
65*cc02d7e2SAndroid Build Coastguard Worker {
66*cc02d7e2SAndroid Build Coastguard Worker     const char utf8[] = "\xF0\x90\xBF\x80";
67*cc02d7e2SAndroid Build Coastguard Worker     const int utf8_len = sizeof(utf8)/sizeof(utf8[0]) - 1;
68*cc02d7e2SAndroid Build Coastguard Worker 
69*cc02d7e2SAndroid Build Coastguard Worker     unsigned char *data = malloc(len);
70*cc02d7e2SAndroid Build Coastguard Worker     unsigned char *p = data;
71*cc02d7e2SAndroid Build Coastguard Worker 
72*cc02d7e2SAndroid Build Coastguard Worker     while (len >= utf8_len) {
73*cc02d7e2SAndroid Build Coastguard Worker         memcpy(p, utf8, utf8_len);
74*cc02d7e2SAndroid Build Coastguard Worker         p += utf8_len;
75*cc02d7e2SAndroid Build Coastguard Worker         len -= utf8_len;
76*cc02d7e2SAndroid Build Coastguard Worker     }
77*cc02d7e2SAndroid Build Coastguard Worker 
78*cc02d7e2SAndroid Build Coastguard Worker     while (len--)
79*cc02d7e2SAndroid Build Coastguard Worker         *p++ = 0x7F;
80*cc02d7e2SAndroid Build Coastguard Worker 
81*cc02d7e2SAndroid Build Coastguard Worker     return data;
82*cc02d7e2SAndroid Build Coastguard Worker }
83*cc02d7e2SAndroid Build Coastguard Worker 
load_test_file(int * len)84*cc02d7e2SAndroid Build Coastguard Worker static unsigned char *load_test_file(int *len)
85*cc02d7e2SAndroid Build Coastguard Worker {
86*cc02d7e2SAndroid Build Coastguard Worker     unsigned char *data;
87*cc02d7e2SAndroid Build Coastguard Worker     int fd;
88*cc02d7e2SAndroid Build Coastguard Worker     struct stat stat;
89*cc02d7e2SAndroid Build Coastguard Worker 
90*cc02d7e2SAndroid Build Coastguard Worker     fd = open("./UTF-8-demo.txt", O_RDONLY);
91*cc02d7e2SAndroid Build Coastguard Worker     if (fd == -1) {
92*cc02d7e2SAndroid Build Coastguard Worker         printf("Failed to open UTF-8-demo.txt!\n");
93*cc02d7e2SAndroid Build Coastguard Worker         exit(1);
94*cc02d7e2SAndroid Build Coastguard Worker     }
95*cc02d7e2SAndroid Build Coastguard Worker     if (fstat(fd, &stat) == -1) {
96*cc02d7e2SAndroid Build Coastguard Worker         printf("Failed to get file size!\n");
97*cc02d7e2SAndroid Build Coastguard Worker         exit(1);
98*cc02d7e2SAndroid Build Coastguard Worker     }
99*cc02d7e2SAndroid Build Coastguard Worker 
100*cc02d7e2SAndroid Build Coastguard Worker     *len = stat.st_size;
101*cc02d7e2SAndroid Build Coastguard Worker     data = malloc(*len);
102*cc02d7e2SAndroid Build Coastguard Worker     if (read(fd, data, *len) != *len) {
103*cc02d7e2SAndroid Build Coastguard Worker         printf("Failed to read file!\n");
104*cc02d7e2SAndroid Build Coastguard Worker         exit(1);
105*cc02d7e2SAndroid Build Coastguard Worker     }
106*cc02d7e2SAndroid Build Coastguard Worker 
107*cc02d7e2SAndroid Build Coastguard Worker     utf8_range(data, *len);
108*cc02d7e2SAndroid Build Coastguard Worker #ifdef __AVX2__
109*cc02d7e2SAndroid Build Coastguard Worker     utf8_range_avx2(data, *len);
110*cc02d7e2SAndroid Build Coastguard Worker #endif
111*cc02d7e2SAndroid Build Coastguard Worker     close(fd);
112*cc02d7e2SAndroid Build Coastguard Worker 
113*cc02d7e2SAndroid Build Coastguard Worker     return data;
114*cc02d7e2SAndroid Build Coastguard Worker }
115*cc02d7e2SAndroid Build Coastguard Worker 
print_test(const unsigned char * data,int len)116*cc02d7e2SAndroid Build Coastguard Worker static void print_test(const unsigned char *data, int len)
117*cc02d7e2SAndroid Build Coastguard Worker {
118*cc02d7e2SAndroid Build Coastguard Worker     while (len--)
119*cc02d7e2SAndroid Build Coastguard Worker         printf("\\x%02X", *data++);
120*cc02d7e2SAndroid Build Coastguard Worker 
121*cc02d7e2SAndroid Build Coastguard Worker     printf("\n");
122*cc02d7e2SAndroid Build Coastguard Worker }
123*cc02d7e2SAndroid Build Coastguard Worker 
124*cc02d7e2SAndroid Build Coastguard Worker struct test {
125*cc02d7e2SAndroid Build Coastguard Worker     const unsigned char *data;
126*cc02d7e2SAndroid Build Coastguard Worker     int len;
127*cc02d7e2SAndroid Build Coastguard Worker };
128*cc02d7e2SAndroid Build Coastguard Worker 
prepare_test_buf(unsigned char * buf,const struct test * pos,int pos_len,int pos_idx)129*cc02d7e2SAndroid Build Coastguard Worker static void prepare_test_buf(unsigned char *buf, const struct test *pos,
130*cc02d7e2SAndroid Build Coastguard Worker                              int pos_len, int pos_idx)
131*cc02d7e2SAndroid Build Coastguard Worker {
132*cc02d7e2SAndroid Build Coastguard Worker     /* Round concatenate correct tokens to 1024 bytes */
133*cc02d7e2SAndroid Build Coastguard Worker     int buf_idx = 0;
134*cc02d7e2SAndroid Build Coastguard Worker     while (buf_idx < 1024) {
135*cc02d7e2SAndroid Build Coastguard Worker         int buf_len = 1024 - buf_idx;
136*cc02d7e2SAndroid Build Coastguard Worker 
137*cc02d7e2SAndroid Build Coastguard Worker         if (buf_len >= pos[pos_idx].len) {
138*cc02d7e2SAndroid Build Coastguard Worker             memcpy(buf+buf_idx, pos[pos_idx].data, pos[pos_idx].len);
139*cc02d7e2SAndroid Build Coastguard Worker             buf_idx += pos[pos_idx].len;
140*cc02d7e2SAndroid Build Coastguard Worker         } else {
141*cc02d7e2SAndroid Build Coastguard Worker             memset(buf+buf_idx, 0, buf_len);
142*cc02d7e2SAndroid Build Coastguard Worker             buf_idx += buf_len;
143*cc02d7e2SAndroid Build Coastguard Worker         }
144*cc02d7e2SAndroid Build Coastguard Worker 
145*cc02d7e2SAndroid Build Coastguard Worker         if (++pos_idx == pos_len)
146*cc02d7e2SAndroid Build Coastguard Worker             pos_idx = 0;
147*cc02d7e2SAndroid Build Coastguard Worker     }
148*cc02d7e2SAndroid Build Coastguard Worker }
149*cc02d7e2SAndroid Build Coastguard Worker 
150*cc02d7e2SAndroid Build Coastguard Worker /* Return 0 on success, -1 on error */
test_manual(const struct ftab * ftab)151*cc02d7e2SAndroid Build Coastguard Worker static int test_manual(const struct ftab *ftab)
152*cc02d7e2SAndroid Build Coastguard Worker {
153*cc02d7e2SAndroid Build Coastguard Worker #pragma GCC diagnostic push
154*cc02d7e2SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wpointer-sign"
155*cc02d7e2SAndroid Build Coastguard Worker     /* positive tests */
156*cc02d7e2SAndroid Build Coastguard Worker     static const struct test pos[] = {
157*cc02d7e2SAndroid Build Coastguard Worker         {"", 0},
158*cc02d7e2SAndroid Build Coastguard Worker         {"\x00", 1},
159*cc02d7e2SAndroid Build Coastguard Worker         {"\x66", 1},
160*cc02d7e2SAndroid Build Coastguard Worker         {"\x7F", 1},
161*cc02d7e2SAndroid Build Coastguard Worker         {"\x00\x7F", 2},
162*cc02d7e2SAndroid Build Coastguard Worker         {"\x7F\x00", 2},
163*cc02d7e2SAndroid Build Coastguard Worker         {"\xC2\x80", 2},
164*cc02d7e2SAndroid Build Coastguard Worker         {"\xDF\xBF", 2},
165*cc02d7e2SAndroid Build Coastguard Worker         {"\xE0\xA0\x80", 3},
166*cc02d7e2SAndroid Build Coastguard Worker         {"\xE0\xA0\xBF", 3},
167*cc02d7e2SAndroid Build Coastguard Worker         {"\xED\x9F\x80", 3},
168*cc02d7e2SAndroid Build Coastguard Worker         {"\xEF\x80\xBF", 3},
169*cc02d7e2SAndroid Build Coastguard Worker         {"\xF0\x90\xBF\x80", 4},
170*cc02d7e2SAndroid Build Coastguard Worker         {"\xF2\x81\xBE\x99", 4},
171*cc02d7e2SAndroid Build Coastguard Worker         {"\xF4\x8F\x88\xAA", 4},
172*cc02d7e2SAndroid Build Coastguard Worker     };
173*cc02d7e2SAndroid Build Coastguard Worker 
174*cc02d7e2SAndroid Build Coastguard Worker     /* negative tests */
175*cc02d7e2SAndroid Build Coastguard Worker     static const struct test neg[] = {
176*cc02d7e2SAndroid Build Coastguard Worker         {"\x80", 1},
177*cc02d7e2SAndroid Build Coastguard Worker         {"\xBF", 1},
178*cc02d7e2SAndroid Build Coastguard Worker         {"\xC0\x80", 2},
179*cc02d7e2SAndroid Build Coastguard Worker         {"\xC1\x00", 2},
180*cc02d7e2SAndroid Build Coastguard Worker         {"\xC2\x7F", 2},
181*cc02d7e2SAndroid Build Coastguard Worker         {"\xDF\xC0", 2},
182*cc02d7e2SAndroid Build Coastguard Worker         {"\xE0\x9F\x80", 3},
183*cc02d7e2SAndroid Build Coastguard Worker         {"\xE0\xC2\x80", 3},
184*cc02d7e2SAndroid Build Coastguard Worker         {"\xED\xA0\x80", 3},
185*cc02d7e2SAndroid Build Coastguard Worker         {"\xED\x7F\x80", 3},
186*cc02d7e2SAndroid Build Coastguard Worker         {"\xEF\x80\x00", 3},
187*cc02d7e2SAndroid Build Coastguard Worker         {"\xF0\x8F\x80\x80", 4},
188*cc02d7e2SAndroid Build Coastguard Worker         {"\xF0\xEE\x80\x80", 4},
189*cc02d7e2SAndroid Build Coastguard Worker         {"\xF2\x90\x91\x7F", 4},
190*cc02d7e2SAndroid Build Coastguard Worker         {"\xF4\x90\x88\xAA", 4},
191*cc02d7e2SAndroid Build Coastguard Worker         {"\xF4\x00\xBF\xBF", 4},
192*cc02d7e2SAndroid Build Coastguard Worker         {"\x00\x00\x00\x00\x00\xC2\x80\x00\x00\x00\xE1\x80\x80\x00\x00\xC2" \
193*cc02d7e2SAndroid Build Coastguard Worker          "\xC2\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
194*cc02d7e2SAndroid Build Coastguard Worker          32},
195*cc02d7e2SAndroid Build Coastguard Worker         {"\x00\x00\x00\x00\x00\xC2\xC2\x80\x00\x00\xE1\x80\x80\x00\x00\x00",
196*cc02d7e2SAndroid Build Coastguard Worker          16},
197*cc02d7e2SAndroid Build Coastguard Worker         {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
198*cc02d7e2SAndroid Build Coastguard Worker          "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF1\x80",
199*cc02d7e2SAndroid Build Coastguard Worker          32},
200*cc02d7e2SAndroid Build Coastguard Worker         {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
201*cc02d7e2SAndroid Build Coastguard Worker          "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF1",
202*cc02d7e2SAndroid Build Coastguard Worker          32},
203*cc02d7e2SAndroid Build Coastguard Worker         {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
204*cc02d7e2SAndroid Build Coastguard Worker          "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF1\x80" \
205*cc02d7e2SAndroid Build Coastguard Worker          "\x80", 33},
206*cc02d7e2SAndroid Build Coastguard Worker         {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
207*cc02d7e2SAndroid Build Coastguard Worker          "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF1\x80" \
208*cc02d7e2SAndroid Build Coastguard Worker          "\xC2\x80", 34},
209*cc02d7e2SAndroid Build Coastguard Worker         {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
210*cc02d7e2SAndroid Build Coastguard Worker          "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xF0" \
211*cc02d7e2SAndroid Build Coastguard Worker          "\x80\x80\x80", 35},
212*cc02d7e2SAndroid Build Coastguard Worker     };
213*cc02d7e2SAndroid Build Coastguard Worker #pragma GCC diagnostic push
214*cc02d7e2SAndroid Build Coastguard Worker 
215*cc02d7e2SAndroid Build Coastguard Worker     /* Test single token */
216*cc02d7e2SAndroid Build Coastguard Worker     for (int i = 0; i < sizeof(pos)/sizeof(pos[0]); ++i) {
217*cc02d7e2SAndroid Build Coastguard Worker         if (ftab->func(pos[i].data, pos[i].len) != 0) {
218*cc02d7e2SAndroid Build Coastguard Worker             printf("FAILED positive test: ");
219*cc02d7e2SAndroid Build Coastguard Worker             print_test(pos[i].data, pos[i].len);
220*cc02d7e2SAndroid Build Coastguard Worker             return -1;
221*cc02d7e2SAndroid Build Coastguard Worker         }
222*cc02d7e2SAndroid Build Coastguard Worker     }
223*cc02d7e2SAndroid Build Coastguard Worker     for (int i = 0; i < sizeof(neg)/sizeof(neg[0]); ++i) {
224*cc02d7e2SAndroid Build Coastguard Worker         if (ftab->func(neg[i].data, neg[i].len) == 0) {
225*cc02d7e2SAndroid Build Coastguard Worker             printf("FAILED negitive test: ");
226*cc02d7e2SAndroid Build Coastguard Worker             print_test(neg[i].data, neg[i].len);
227*cc02d7e2SAndroid Build Coastguard Worker             return -1;
228*cc02d7e2SAndroid Build Coastguard Worker         }
229*cc02d7e2SAndroid Build Coastguard Worker     }
230*cc02d7e2SAndroid Build Coastguard Worker 
231*cc02d7e2SAndroid Build Coastguard Worker     /* Test shifted buffer to cover 1k length */
232*cc02d7e2SAndroid Build Coastguard Worker     /* buffer size must be greater than 1024 + 16 + max(test string length) */
233*cc02d7e2SAndroid Build Coastguard Worker     const int max_size = 1024*2;
234*cc02d7e2SAndroid Build Coastguard Worker     uint64_t buf64[max_size/8 + 2];
235*cc02d7e2SAndroid Build Coastguard Worker     /* Offset 8 bytes by 1 byte */
236*cc02d7e2SAndroid Build Coastguard Worker     unsigned char *buf = ((unsigned char *)buf64) + 1;
237*cc02d7e2SAndroid Build Coastguard Worker     int buf_len;
238*cc02d7e2SAndroid Build Coastguard Worker 
239*cc02d7e2SAndroid Build Coastguard Worker     for (int i = 0; i < sizeof(pos)/sizeof(pos[0]); ++i) {
240*cc02d7e2SAndroid Build Coastguard Worker         /* Positive test: shift 16 bytes, validate each shift */
241*cc02d7e2SAndroid Build Coastguard Worker         prepare_test_buf(buf, pos, sizeof(pos)/sizeof(pos[0]), i);
242*cc02d7e2SAndroid Build Coastguard Worker         buf_len = 1024;
243*cc02d7e2SAndroid Build Coastguard Worker         for (int j = 0; j < 16; ++j) {
244*cc02d7e2SAndroid Build Coastguard Worker             if (ftab->func(buf, buf_len) != 0) {
245*cc02d7e2SAndroid Build Coastguard Worker                 printf("FAILED positive test: ");
246*cc02d7e2SAndroid Build Coastguard Worker                 print_test(buf, buf_len);
247*cc02d7e2SAndroid Build Coastguard Worker                 return -1;
248*cc02d7e2SAndroid Build Coastguard Worker             }
249*cc02d7e2SAndroid Build Coastguard Worker             for (int k = buf_len; k >= 1; --k)
250*cc02d7e2SAndroid Build Coastguard Worker                 buf[k] = buf[k-1];
251*cc02d7e2SAndroid Build Coastguard Worker             buf[0] = '\x55';
252*cc02d7e2SAndroid Build Coastguard Worker             ++buf_len;
253*cc02d7e2SAndroid Build Coastguard Worker         }
254*cc02d7e2SAndroid Build Coastguard Worker 
255*cc02d7e2SAndroid Build Coastguard Worker         /* Negative test: trunk last non ascii */
256*cc02d7e2SAndroid Build Coastguard Worker         while (buf_len >= 1 && buf[buf_len-1] <= 0x7F)
257*cc02d7e2SAndroid Build Coastguard Worker             --buf_len;
258*cc02d7e2SAndroid Build Coastguard Worker         if (buf_len && ftab->func(buf, buf_len-1) == 0) {
259*cc02d7e2SAndroid Build Coastguard Worker             printf("FAILED negitive test: ");
260*cc02d7e2SAndroid Build Coastguard Worker             print_test(buf, buf_len);
261*cc02d7e2SAndroid Build Coastguard Worker             return -1;
262*cc02d7e2SAndroid Build Coastguard Worker         }
263*cc02d7e2SAndroid Build Coastguard Worker     }
264*cc02d7e2SAndroid Build Coastguard Worker 
265*cc02d7e2SAndroid Build Coastguard Worker     /* Negative test */
266*cc02d7e2SAndroid Build Coastguard Worker     for (int i = 0; i < sizeof(neg)/sizeof(neg[0]); ++i) {
267*cc02d7e2SAndroid Build Coastguard Worker         /* Append one error token, shift 16 bytes, validate each shift */
268*cc02d7e2SAndroid Build Coastguard Worker         int pos_idx = i % (sizeof(pos)/sizeof(pos[0]));
269*cc02d7e2SAndroid Build Coastguard Worker         prepare_test_buf(buf, pos, sizeof(pos)/sizeof(pos[0]), pos_idx);
270*cc02d7e2SAndroid Build Coastguard Worker         memcpy(buf+1024, neg[i].data, neg[i].len);
271*cc02d7e2SAndroid Build Coastguard Worker         buf_len = 1024 + neg[i].len;
272*cc02d7e2SAndroid Build Coastguard Worker         for (int j = 0; j < 16; ++j) {
273*cc02d7e2SAndroid Build Coastguard Worker             if (ftab->func(buf, buf_len) == 0) {
274*cc02d7e2SAndroid Build Coastguard Worker                 printf("FAILED negative test: ");
275*cc02d7e2SAndroid Build Coastguard Worker                 print_test(buf, buf_len);
276*cc02d7e2SAndroid Build Coastguard Worker                 return -1;
277*cc02d7e2SAndroid Build Coastguard Worker             }
278*cc02d7e2SAndroid Build Coastguard Worker             for (int k = buf_len; k >= 1; --k)
279*cc02d7e2SAndroid Build Coastguard Worker                 buf[k] = buf[k-1];
280*cc02d7e2SAndroid Build Coastguard Worker             buf[0] = '\x66';
281*cc02d7e2SAndroid Build Coastguard Worker             ++buf_len;
282*cc02d7e2SAndroid Build Coastguard Worker         }
283*cc02d7e2SAndroid Build Coastguard Worker     }
284*cc02d7e2SAndroid Build Coastguard Worker 
285*cc02d7e2SAndroid Build Coastguard Worker     return 0;
286*cc02d7e2SAndroid Build Coastguard Worker }
287*cc02d7e2SAndroid Build Coastguard Worker 
test(const unsigned char * data,int len,const struct ftab * ftab)288*cc02d7e2SAndroid Build Coastguard Worker static int test(const unsigned char *data, int len, const struct ftab *ftab)
289*cc02d7e2SAndroid Build Coastguard Worker {
290*cc02d7e2SAndroid Build Coastguard Worker     int ret_standard = ftab->func(data, len);
291*cc02d7e2SAndroid Build Coastguard Worker     int ret_manual = test_manual(ftab);
292*cc02d7e2SAndroid Build Coastguard Worker     printf("%s\n", ftab->name);
293*cc02d7e2SAndroid Build Coastguard Worker     printf("standard test: %s\n", ret_standard ? "FAIL" : "pass");
294*cc02d7e2SAndroid Build Coastguard Worker     printf("manual test: %s\n", ret_manual ? "FAIL" : "pass");
295*cc02d7e2SAndroid Build Coastguard Worker 
296*cc02d7e2SAndroid Build Coastguard Worker     return ret_standard | ret_manual;
297*cc02d7e2SAndroid Build Coastguard Worker }
298*cc02d7e2SAndroid Build Coastguard Worker 
bench(const unsigned char * data,int len,const struct ftab * ftab)299*cc02d7e2SAndroid Build Coastguard Worker static int bench(const unsigned char *data, int len, const struct ftab *ftab)
300*cc02d7e2SAndroid Build Coastguard Worker {
301*cc02d7e2SAndroid Build Coastguard Worker     const int loops = 1024*1024*1024/len;
302*cc02d7e2SAndroid Build Coastguard Worker     int ret = 0;
303*cc02d7e2SAndroid Build Coastguard Worker     double time, size;
304*cc02d7e2SAndroid Build Coastguard Worker     struct timeval tv1, tv2;
305*cc02d7e2SAndroid Build Coastguard Worker 
306*cc02d7e2SAndroid Build Coastguard Worker     fprintf(stderr, "bench %s... ", ftab->name);
307*cc02d7e2SAndroid Build Coastguard Worker     gettimeofday(&tv1, 0);
308*cc02d7e2SAndroid Build Coastguard Worker     for (int i = 0; i < loops; ++i)
309*cc02d7e2SAndroid Build Coastguard Worker         ret |= ftab->func(data, len);
310*cc02d7e2SAndroid Build Coastguard Worker     gettimeofday(&tv2, 0);
311*cc02d7e2SAndroid Build Coastguard Worker     printf("%s\n", ret?"FAIL":"pass");
312*cc02d7e2SAndroid Build Coastguard Worker 
313*cc02d7e2SAndroid Build Coastguard Worker     time = tv2.tv_usec - tv1.tv_usec;
314*cc02d7e2SAndroid Build Coastguard Worker     time = time / 1000000 + tv2.tv_sec - tv1.tv_sec;
315*cc02d7e2SAndroid Build Coastguard Worker     size = ((double)len * loops) / (1024*1024);
316*cc02d7e2SAndroid Build Coastguard Worker     printf("time: %.4f s\n", time);
317*cc02d7e2SAndroid Build Coastguard Worker     printf("data: %.0f MB\n", size);
318*cc02d7e2SAndroid Build Coastguard Worker     printf("BW: %.2f MB/s\n", size / time);
319*cc02d7e2SAndroid Build Coastguard Worker 
320*cc02d7e2SAndroid Build Coastguard Worker     return 0;
321*cc02d7e2SAndroid Build Coastguard Worker }
322*cc02d7e2SAndroid Build Coastguard Worker 
usage(const char * bin)323*cc02d7e2SAndroid Build Coastguard Worker static void usage(const char *bin)
324*cc02d7e2SAndroid Build Coastguard Worker {
325*cc02d7e2SAndroid Build Coastguard Worker     printf("Usage:\n");
326*cc02d7e2SAndroid Build Coastguard Worker     printf("%s test  [alg]      ==> test all or one algorithm\n", bin);
327*cc02d7e2SAndroid Build Coastguard Worker     printf("%s bench [alg]      ==> benchmark all or one algorithm\n", bin);
328*cc02d7e2SAndroid Build Coastguard Worker     printf("%s bench size NUM   ==> benchmark with specific buffer size\n", bin);
329*cc02d7e2SAndroid Build Coastguard Worker     printf("alg = ");
330*cc02d7e2SAndroid Build Coastguard Worker     for (int i = 0; i < sizeof(ftab)/sizeof(ftab[0]); ++i)
331*cc02d7e2SAndroid Build Coastguard Worker         printf("%s ", ftab[i].name);
332*cc02d7e2SAndroid Build Coastguard Worker     printf("\nNUM = buffer size in bytes, 1 ~ 67108864(64M)\n");
333*cc02d7e2SAndroid Build Coastguard Worker }
334*cc02d7e2SAndroid Build Coastguard Worker 
main(int argc,char * argv[])335*cc02d7e2SAndroid Build Coastguard Worker int main(int argc, char *argv[])
336*cc02d7e2SAndroid Build Coastguard Worker {
337*cc02d7e2SAndroid Build Coastguard Worker     int len = 0;
338*cc02d7e2SAndroid Build Coastguard Worker     unsigned char *data;
339*cc02d7e2SAndroid Build Coastguard Worker     const char *alg = NULL;
340*cc02d7e2SAndroid Build Coastguard Worker     int (*tb)(const unsigned char *data, int len, const struct ftab *ftab);
341*cc02d7e2SAndroid Build Coastguard Worker 
342*cc02d7e2SAndroid Build Coastguard Worker     tb = NULL;
343*cc02d7e2SAndroid Build Coastguard Worker     if (argc >= 2) {
344*cc02d7e2SAndroid Build Coastguard Worker         if (strcmp(argv[1], "test") == 0)
345*cc02d7e2SAndroid Build Coastguard Worker             tb = test;
346*cc02d7e2SAndroid Build Coastguard Worker         else if (strcmp(argv[1], "bench") == 0)
347*cc02d7e2SAndroid Build Coastguard Worker             tb = bench;
348*cc02d7e2SAndroid Build Coastguard Worker         if (argc >= 3) {
349*cc02d7e2SAndroid Build Coastguard Worker             alg = argv[2];
350*cc02d7e2SAndroid Build Coastguard Worker             if (strcmp(alg, "size") == 0) {
351*cc02d7e2SAndroid Build Coastguard Worker                 if (argc < 4) {
352*cc02d7e2SAndroid Build Coastguard Worker                     tb = NULL;
353*cc02d7e2SAndroid Build Coastguard Worker                 } else {
354*cc02d7e2SAndroid Build Coastguard Worker                     alg = NULL;
355*cc02d7e2SAndroid Build Coastguard Worker                     len = atoi(argv[3]);
356*cc02d7e2SAndroid Build Coastguard Worker                     if (len <= 0 || len > 67108864) {
357*cc02d7e2SAndroid Build Coastguard Worker                         printf("Buffer size error!\n\n");
358*cc02d7e2SAndroid Build Coastguard Worker                         tb = NULL;
359*cc02d7e2SAndroid Build Coastguard Worker                     }
360*cc02d7e2SAndroid Build Coastguard Worker                 }
361*cc02d7e2SAndroid Build Coastguard Worker             }
362*cc02d7e2SAndroid Build Coastguard Worker         }
363*cc02d7e2SAndroid Build Coastguard Worker     }
364*cc02d7e2SAndroid Build Coastguard Worker 
365*cc02d7e2SAndroid Build Coastguard Worker     if (tb == NULL) {
366*cc02d7e2SAndroid Build Coastguard Worker         usage(argv[0]);
367*cc02d7e2SAndroid Build Coastguard Worker         return 1;
368*cc02d7e2SAndroid Build Coastguard Worker     }
369*cc02d7e2SAndroid Build Coastguard Worker 
370*cc02d7e2SAndroid Build Coastguard Worker     /* Load UTF8 test buffer */
371*cc02d7e2SAndroid Build Coastguard Worker     if (len)
372*cc02d7e2SAndroid Build Coastguard Worker         data = load_test_buf(len);
373*cc02d7e2SAndroid Build Coastguard Worker     else
374*cc02d7e2SAndroid Build Coastguard Worker         data = load_test_file(&len);
375*cc02d7e2SAndroid Build Coastguard Worker 
376*cc02d7e2SAndroid Build Coastguard Worker     int ret = 0;
377*cc02d7e2SAndroid Build Coastguard Worker     if (tb == bench)
378*cc02d7e2SAndroid Build Coastguard Worker         printf("=============== Bench UTF8 (%d bytes) ===============\n", len);
379*cc02d7e2SAndroid Build Coastguard Worker     for (int i = 0; i < sizeof(ftab)/sizeof(ftab[0]); ++i) {
380*cc02d7e2SAndroid Build Coastguard Worker         if (alg && strcmp(alg, ftab[i].name) != 0)
381*cc02d7e2SAndroid Build Coastguard Worker             continue;
382*cc02d7e2SAndroid Build Coastguard Worker         ret |= tb((const unsigned char *)data, len, &ftab[i]);
383*cc02d7e2SAndroid Build Coastguard Worker         printf("\n");
384*cc02d7e2SAndroid Build Coastguard Worker     }
385*cc02d7e2SAndroid Build Coastguard Worker 
386*cc02d7e2SAndroid Build Coastguard Worker #if 0
387*cc02d7e2SAndroid Build Coastguard Worker     if (tb == bench) {
388*cc02d7e2SAndroid Build Coastguard Worker         printf("==================== Bench ASCII ====================\n");
389*cc02d7e2SAndroid Build Coastguard Worker         /* Change test buffer to ascii */
390*cc02d7e2SAndroid Build Coastguard Worker         for (int i = 0; i < len; i++)
391*cc02d7e2SAndroid Build Coastguard Worker             data[i] &= 0x7F;
392*cc02d7e2SAndroid Build Coastguard Worker 
393*cc02d7e2SAndroid Build Coastguard Worker         for (int i = 0; i < sizeof(ftab)/sizeof(ftab[0]); ++i) {
394*cc02d7e2SAndroid Build Coastguard Worker             if (alg && strcmp(alg, ftab[i].name) != 0)
395*cc02d7e2SAndroid Build Coastguard Worker                 continue;
396*cc02d7e2SAndroid Build Coastguard Worker             tb((const unsigned char *)data, len, &ftab[i]);
397*cc02d7e2SAndroid Build Coastguard Worker             printf("\n");
398*cc02d7e2SAndroid Build Coastguard Worker         }
399*cc02d7e2SAndroid Build Coastguard Worker     }
400*cc02d7e2SAndroid Build Coastguard Worker #endif
401*cc02d7e2SAndroid Build Coastguard Worker 
402*cc02d7e2SAndroid Build Coastguard Worker     free(data);
403*cc02d7e2SAndroid Build Coastguard Worker 
404*cc02d7e2SAndroid Build Coastguard Worker     return ret;
405*cc02d7e2SAndroid Build Coastguard Worker }
406