1 #include <stdint.h>
2 #include <inttypes.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdio.h>
6 #include "opcodes.h"
7 
8 #ifndef M3
9 #define M3 0
10 #endif
11 
12 /* The abstracted result of an CU12 insn */
13 typedef struct {
14    uint64_t addr1;  // target
15    uint64_t len1;
16    uint64_t addr2;  // source
17    uint64_t len2;
18    uint32_t cc;
19 } cu12_t;
20 
21 /* Define various input buffers. */
22 
23 /* 1-byte UTF-8 character */
24 uint8_t pattern1[] = {
25    0x00, 0x01, 0x02, 0x03
26 };
27 
28 /* 2-byte UTF-8 character */
29 uint8_t pattern2[] = {
30    0xc2, 0x80,
31    0xc2, 0x81,
32    0xc2, 0x82,
33    0xc2, 0x83,
34 };
35 
36 /* 3-byte UTF-8 character */
37 uint8_t pattern3[] = {
38    0xe1, 0x80, 0x80,
39    0xe1, 0x80, 0x81,
40    0xe1, 0x80, 0x82,
41    0xe1, 0x80, 0x83,
42 };
43 
44 /* 4-byte UTF-8 character */
45 uint8_t pattern4[] = {
46    0xf4, 0x80, 0x80, 0x80,
47    0xf4, 0x80, 0x80, 0x81,
48    0xf4, 0x80, 0x80, 0x82,
49    0xf4, 0x80, 0x80, 0x83,
50 };
51 
52 
53 /* Mixed bytes */
54 uint8_t mixed[] = {
55    0x01,                    // 1 byte
56    0xc3, 0x80,              // 2 bytes
57    0x12,                    // 1 byte
58    0xe1, 0x90, 0x93,        // 3 bytes
59    0x23,                    // 1 byte
60    0xf4, 0x80, 0x90, 0x8a,  // 4 bytes
61    0x34,                    // 1 byte
62    0xc4, 0x8c,              // 2 bytes
63    0xe1, 0x91, 0x94,        // 3 bytes
64    0xc5, 0x8a,              // 2 bytes
65    0xf4, 0x80, 0x90, 0x8a,  // 4 bytes
66    0xc5, 0x8a,              // 2 bytes
67    0xe1, 0x91, 0x94,        // 3 bytes
68    0xf4, 0x80, 0x90, 0x8a,  // 4 bytes
69    0xe1, 0x91, 0x94,        // 3 bytes
70 };
71 
72 /* This is the buffer for the converted bytes. */
73 uint16_t buff[1000];  /* Large so we con'don't have to worry about it */
74 
75 
76 static cu12_t
do_cu12(uint16_t * dst,uint64_t dst_len,uint8_t * src,uint64_t src_len)77 do_cu12(uint16_t *dst, uint64_t dst_len, uint8_t *src, uint64_t src_len)
78 {
79    int cc = 42;
80    cu12_t regs;
81 
82    /* build up the register pairs */
83    register uint8_t  *source     asm("4") = src;
84    register uint64_t  source_len asm("5") = src_len;
85    register uint16_t *dest       asm("2") = dst;
86    register uint64_t  dest_len   asm("3") = dst_len;
87 
88    asm volatile(
89                 CU12(M3,2,4)
90                 "ipm %2\n\t"
91                 "srl %2,28\n\t"
92                 : "+d"(dest), "+d"(source), "=d"(cc),
93                   "+d"(source_len), "+d"(dest_len)
94                 :
95                 : "memory", "cc");
96 
97    /* Capture register contents at end of cu12 */
98    regs.addr1 = (uint64_t)dest;
99    regs.len1  = dest_len;
100    regs.addr2 = (uint64_t)source;
101    regs.len2  = source_len;
102    regs.cc = cc;
103 
104    return regs;
105 }
106 
107 void
run_test(uint16_t * dst,uint64_t dst_len,uint8_t * src,uint64_t src_len)108 run_test(uint16_t *dst, uint64_t dst_len, uint8_t *src, uint64_t src_len)
109 {
110    int i;
111    cu12_t result;
112 
113    printf("UTF8:  ");
114    if (src_len == 0)
115       printf(" <none>");
116    else {
117       for(i = 0; i < src_len; ++i)
118          printf(" %02x", src[i]);
119    }
120    printf("\n");
121 
122    result = do_cu12(dst, dst_len, src, src_len);
123 
124    // Write out the converted byte, if any
125    printf("UTF16: ");
126    if (dst_len - result.len1 == 0)
127       printf(" <none>");
128    else {
129       uint64_t num_bytes = dst_len - result.len1;
130 
131       /* The number of bytes that were written must be divisible by 2 */
132       if (num_bytes % 2 != 0)
133          fprintf(stderr, "*** number of bytes is not a multiple of 2\n");
134 
135       for (i = 0; i < num_bytes / 2; i++) {
136          printf(" %04x", dst[i]);
137       }
138    }
139    printf("\n");
140 
141    printf("  cc = %d\n", result.cc);
142    if (dst != NULL)
143       printf("  dst address difference: %"PRId64, result.addr1 - (uint64_t)dst);
144    printf("  dst len: %"PRId64"\n", result.len1);
145 
146    if (src != NULL)
147       printf("  src address difference: %"PRId64, result.addr2 - (uint64_t)src);
148    printf("  src len: %"PRId64"\n", result.len2);
149 }
150 
151 // Test conversion of a one-byte character
convert_1_byte(void)152 void convert_1_byte(void)
153 {
154    int i;
155 
156    printf("===== Conversion of a one-byte character =====\n");
157 
158    printf("\n----- Valid characters -----\n");
159    uint8_t valid[] = {
160       0x00, 0x7f,              // corner cases
161       0x01, 0x10, 0x7e, 0x5d   // misc
162    };
163    run_test(buff, sizeof buff, valid, sizeof valid);
164 
165    // As conversion stops upon encountering an invalid character, we
166    // need to test each invalid character separately, to make sure it
167    // is recognized as invalid.
168 
169    printf("\n----- Invalid characters -----\n");
170    uint8_t always_invalid[] = {
171       0x80, 0xbf,              // corner cases
172       0xf8, 0xff,              // corner cases
173       0x81, 0xbe, 0x95, 0xab   // misc
174    };
175    for (i = 0; i < sizeof always_invalid; ++i) {
176       uint8_t invalid_char[1];
177       invalid_char[0] = always_invalid[i];
178       run_test(buff, sizeof buff, invalid_char, sizeof invalid_char);
179    }
180 
181    // In case of m3 == 0 we get cc=0 indicating exhaustion of source
182    printf("\n----- Invalid characters if m3 == 1 -----\n");
183    uint8_t invalid_if_m3[] = {  // contains all such invalid characters
184       0xc0, 0xc1,
185       0xf5, 0xf6, 0xf7
186    };
187    for (i = 0; i < sizeof invalid_if_m3; ++i) {
188       uint8_t invalid_char[1];
189       invalid_char[0] = invalid_if_m3[i];
190       run_test(buff, sizeof buff, invalid_char, sizeof invalid_char);
191    }
192 
193    printf("\n----- 1st char valid, 2nd char invalid -----\n");
194    uint8_t valid_invalid[] = {
195       0x10, // valid
196       0xaa  // invalid
197    };
198    run_test(buff, sizeof buff, valid_invalid, sizeof valid_invalid);
199 }
200 
201 // Test conversion of a two-byte character
convert_2_bytes(void)202 void convert_2_bytes(void)
203 {
204    int i;
205 
206    printf("\n===== Conversion of a two-byte character =====\n");
207 
208    printf("\n----- Valid characters -----\n");
209    uint8_t valid[] = {
210       0xc2, 0x80,             // corner case
211       0xc2, 0xbf,             // corner case
212       0xdf, 0x80,             // corner case
213       0xdf, 0xbf,             // corner case
214       0xc3, 0xbe, 0xda, 0xbc  // misc
215    };
216    run_test(buff, sizeof buff, valid, sizeof valid);
217 
218    printf("\n----- Valid characters if m3 == 0 -----\n");
219    // First char is 0xc0 or 0xc1
220    uint8_t valid_if_not_m3[] = {
221       0xc0, 0x80,
222       0xc0, 0xbf,
223       0xc1, 0x80,
224       0xc0, 0xbf
225    };
226    run_test(buff, sizeof buff, valid_if_not_m3, sizeof valid_if_not_m3);
227 
228    // Test for invalid two-byte characters where the 1st byte is valid
229    // The 2nd byte is invalid if not in range 0x80..0xbf, inclusive
230 
231    // As conversion stops upon encountering an invalid character, we
232    // need to test each invalid character separately, to make sure it
233    // is recognized as invalid.
234 
235    printf("\n----- Invalid characters if m3 == 1 -----\n");
236    uint8_t always_invalid[] = {
237       0xc2, 0x00,
238       0xc2, 0x7f,
239       0xc2, 0xc0,
240       0xc2, 0xff
241    };
242    for (i = 0; i < sizeof always_invalid; i += 2) {
243       uint8_t invalid_char[2];
244       invalid_char[0] = always_invalid[i];
245       invalid_char[1] = always_invalid[i+1];
246       run_test(buff, sizeof buff, invalid_char, sizeof invalid_char);
247    }
248 
249    /* Nb: for a two-byte character we need not test the case where
250       invalidity of the character (cc=2) takes precedence over exhaustion
251       of the 1st operand (cc=1). Invalidity of the character has already
252       been tested when testing the 1st byte. */
253 
254    printf("\n----- 1st char valid, 2nd char invalid -----\n");
255    uint8_t valid_invalid[] = {
256       0xc3, 0x81, // valid
257       0xc4, 0x00  // invalid
258    };
259    run_test(buff, sizeof buff, valid_invalid, sizeof valid_invalid);
260 }
261 
262 // Test conversion of a three-byte character
263 void
convert_3_bytes(void)264 convert_3_bytes(void)
265 {
266    int i;
267 
268    printf("\n===== Conversion of a three-byte character =====\n");
269 
270    /* Exhaustively test the 1st byte E0 - EF, and the interval boundaries for
271       the 2nd and 3rd bytes */
272    printf("\n----- Valid characters -----\n");
273    uint8_t e0[] = {
274       0xe0, 0xa0, 0x80,
275       0xe0, 0xbf, 0x80,
276       0xe0, 0xa0, 0xbf,
277       0xe0, 0xbf, 0xbf,
278       0xe0, 0xaa, 0xbb,   // random  e0 .. ..
279    };
280    run_test(buff, sizeof buff, e0, sizeof e0);
281 
282    uint8_t ed[] = {
283       0xed, 0x80, 0x80,
284       0xed, 0x9f, 0x80,
285       0xed, 0x80, 0xbf,
286       0xed, 0x9f, 0xbf,
287       0xed, 0x8a, 0xbb,   // random  ed .. ..
288    };
289    run_test(buff, sizeof buff, ed, sizeof ed);
290 
291    for (i = 0; i <= 0xf; ++i) {
292       uint8_t exxx_1[3] = { 0x0, 0x80, 0x80 };
293       uint8_t exxx_2[3] = { 0x0, 0xbf, 0x80 };
294       uint8_t exxx_3[3] = { 0x0, 0x80, 0xbf };
295       uint8_t exxx_4[3] = { 0x0, 0xbf, 0xbf };
296 
297       if (i == 0x00) continue;   // special case e0
298       if (i == 0x0d) continue;   // special case ed
299 
300       exxx_1[0] = 0xe0 | i;
301       exxx_2[0] = 0xe0 | i;
302       exxx_3[0] = 0xe0 | i;
303       exxx_4[0] = 0xe0 | i;
304       run_test(buff, sizeof buff, exxx_1, sizeof exxx_1);
305       run_test(buff, sizeof buff, exxx_2, sizeof exxx_2);
306       run_test(buff, sizeof buff, exxx_3, sizeof exxx_3);
307       run_test(buff, sizeof buff, exxx_4, sizeof exxx_4);
308    };
309 
310    printf("\n----- Invalid characters (2nd byte is invalid) -----\n");
311    // Test for invalid three-byte characters where the 1st byte is valid
312    // The 2nd byte is invalid.
313 
314    // As conversion stops upon encountering an invalid character, we
315    // need to test each invalid character separately, to make sure it
316    // is recognized as invalid.
317 
318    e0[0] = 0xe0;  // valid
319    e0[1] = 0x9f;  // invalid  because outside [0xa0 .. 0xbf]
320    e0[2] = 0x80;  // valid
321    run_test(buff, sizeof buff, e0, sizeof e0);
322    e0[1] = 0xc0;  // invalid  because outside [0xa0 .. 0xbf]
323    run_test(buff, sizeof buff, e0, sizeof e0);
324 
325    ed[0] = 0xed;  // valid
326    ed[1] = 0x7f;  // invalid  because outside [0x80 .. 0x9f]
327    ed[2] = 0x80;  // valid
328    run_test(buff, sizeof buff, ed, sizeof ed);
329    ed[1] = 0xa0;  // invalid  because outside [0x80 .. 0x9f]
330    run_test(buff, sizeof buff, ed, sizeof ed);
331 
332    for (i = 0; i <= 0xf; ++i) {
333       uint8_t exxx_1[3] = { 0x0, 0x7f, 0x80 };
334       uint8_t exxx_2[3] = { 0x0, 0xc0, 0x80 };
335 
336       if (i == 0x00) continue;   // special case e0
337       if (i == 0x0d) continue;   // special case ed
338 
339       exxx_1[0] = 0xe0 | i;
340       exxx_2[0] = 0xe0 | i;
341       run_test(buff, sizeof buff, exxx_1, sizeof exxx_1);
342       run_test(buff, sizeof buff, exxx_2, sizeof exxx_2);
343    };
344 
345    printf("\n----- Invalid characters (3rd byte is invalid) -----\n");
346    // For all 1st bytes 0xe0 .. 0xef the 3rd bytes must be in [0x80 .. 0xbf]
347    // No need to special case 0xe0 and 0xed
348    for (i = 0; i <= 0xf; ++i) {
349       uint8_t exxx_1[3] = { 0x0, 0xab, 0x7f };
350       uint8_t exxx_2[3] = { 0x0, 0xab, 0xc0 };
351 
352       exxx_1[0] = 0xe0 | i;
353       exxx_2[0] = 0xe0 | i;
354       run_test(buff, sizeof buff, exxx_1, sizeof exxx_1);
355       run_test(buff, sizeof buff, exxx_2, sizeof exxx_2);
356    };
357 
358    printf("\n----- Invalid 2nd char AND output exhausted -----\n");
359    /* The character is invalid in its 2nd byte AND the output buffer is
360       exhausted (2 bytes are needed) */
361    uint8_t pat1[] = {
362       0xe0, 0x00, 0x80
363    };
364    run_test(buff, 1, pat1, 3);
365 
366    printf("\n----- Invalid 3rd char AND output exhausted -----\n");
367    /* The character is invalid in its 3rd byte AND the output buffer is
368       exhausted (2 bytes are needed) */
369    uint8_t pat2[] = {
370       0xe4, 0x84, 0x00
371    };
372    run_test(buff, 1, pat2, 3);
373 
374    printf("\n----- 1st char valid, 2nd char invalid -----\n");
375    uint8_t valid_invalid[] = {
376       0xe1, 0x90, 0x90, // valid
377       0xe1, 0x00, 0x90  // invalid
378    };
379    run_test(buff, sizeof buff, valid_invalid, sizeof valid_invalid);
380 }
381 
382 // Test conversion of a four-byte character
383 void
convert_4_bytes(void)384 convert_4_bytes(void)
385 {
386    int i, j;
387 
388    printf("\n===== Conversion of a four-byte character =====\n");
389 
390    printf("\n----- Valid characters -----\n");
391    for (i = 0; i <= 4; ++i) {
392       uint8_t valid[4];
393 
394       valid[0] = 0xf0 | i;
395 
396       for (j = 0; j <= 1; ++j) {
397          // Byte 2
398          if (i == 0) {
399             valid[1] = j == 0 ? 0x90 : 0xbf;    // 0xf0
400          } else if (i == 4) {
401             valid[1] = j == 0 ? 0x80 : 0x8f;    // 0xf4
402          } else {
403             valid[1] = j == 0 ? 0x80 : 0xbf;    // 0xf1 .. 0xf3
404          }
405          // Byte 3 and byte 4 have same interval 0x80 .. 0xbf
406          valid[2] = 0x80;
407          valid[3] = 0x80;
408          run_test(buff, sizeof buff, valid, sizeof valid);
409          valid[2] = 0x80;
410          valid[3] = 0xbf;
411          run_test(buff, sizeof buff, valid, sizeof valid);
412          valid[2] = 0xbf;
413          valid[3] = 0x80;
414          run_test(buff, sizeof buff, valid, sizeof valid);
415          valid[2] = 0xbf;
416          valid[3] = 0xbf;
417          run_test(buff, sizeof buff, valid, sizeof valid);
418       }
419    }
420 
421    printf("\n----- Valid characters if m3 == 0 -----\n");
422    // First char is 0xf5 .. 0xf7
423    uint8_t valid_if_not_m3[] = {
424       0xf5, 0x00, 0x00, 0x00,
425       0xf6, 0x11, 0x22, 0x33,
426       0xf7, 0x44, 0x55, 0x66,
427    };
428    run_test(buff, sizeof buff, valid_if_not_m3, sizeof valid_if_not_m3);
429 
430    // As conversion stops upon encountering an invalid character, we
431    // need to test each invalid character separately, to make sure it
432    // is recognized as invalid.
433 
434    printf("\n----- Invalid characters (2nd byte is invalid) -----\n");
435    // Test for invalid four-byte characters where the 2nd byte is invalid.
436    // All other bytes are valid
437    uint8_t f0[4], f4[4];
438 
439    f0[0] = 0xf0;  // valid
440    f0[1] = 0x8f;  // invalid  because outside [0x90 .. 0xbf]
441    f0[2] = 0x80;  // valid
442    f0[3] = 0x80;  // valid
443    run_test(buff, sizeof buff, f0, sizeof f0);
444    f0[1] = 0xc0;  // invalid  because outside [0x90 .. 0xbf]
445    run_test(buff, sizeof buff, f0, sizeof f0);
446 
447    f4[0] = 0xf4;  // valid
448    f4[1] = 0x7f;  // invalid  because outside [0x80 .. 0x8f]
449    f4[2] = 0x80;  // valid
450    f4[3] = 0x80;  // valid
451    run_test(buff, sizeof buff, f4, sizeof f4);
452    f4[1] = 0x90;  // invalid  because outside [0x80 .. 0x9f]
453    run_test(buff, sizeof buff, f4, sizeof f4);
454 
455    for (i = 0; i <= 0x4; ++i) {
456       uint8_t fxxx_1[4] = { 0x0, 0x7f, 0x80, 0x80 };
457       uint8_t fxxx_2[4] = { 0x0, 0xc0, 0x80, 0x80 };
458 
459       if (i == 0) continue;   // special case f0
460       if (i == 4) continue;   // special case f4
461 
462       fxxx_1[0] = 0xf0 | i;
463       fxxx_2[0] = 0xf0 | i;
464       run_test(buff, sizeof buff, fxxx_1, sizeof fxxx_1);
465       run_test(buff, sizeof buff, fxxx_2, sizeof fxxx_2);
466    };
467 
468    printf("\n----- Invalid characters (3rd byte is invalid) -----\n");
469    // Test for invalid four-byte characters where the 3rd byte is invalid.
470    // All other bytes are valid
471    for (i = 0; i <= 0x4; ++i) {
472       uint8_t fxxx[4] = { 0x0, 0x0, 0x0, 0x80 };
473 
474       fxxx[0] = 0xf0 | i;
475       fxxx[1] = (i == 0) ? 0x94 : 0x84;
476       fxxx[2] = 0x7f;
477       run_test(buff, sizeof buff, fxxx, sizeof fxxx);
478       fxxx[2] = 0xc0;
479       run_test(buff, sizeof buff, fxxx, sizeof fxxx);
480    };
481 
482    printf("\n----- Invalid characters (4th byte is invalid) -----\n");
483    // Test for invalid four-byte characters where the 3rd byte is invalid.
484    // All other bytes are valid
485    for (i = 0; i <= 0x4; ++i) {
486       uint8_t fxxx[4] = { 0x0, 0x0, 0x80, 0x0 };
487 
488       fxxx[0] = 0xf0 | i;
489       fxxx[1] = (i == 0) ? 0x94 : 0x84;
490       fxxx[3] = 0x7f;
491       run_test(buff, sizeof buff, fxxx, sizeof fxxx);
492       fxxx[3] = 0xc0;
493       run_test(buff, sizeof buff, fxxx, sizeof fxxx);
494    };
495 
496    printf("\n----- Invalid 2nd char AND output exhausted -----\n");
497    /* The character is invalid in its 2nd byte AND the output buffer is
498       exhausted (4 bytes are needed) */
499    uint8_t pat1[] = {
500       0xf0, 0x00, 0x80, 0x80
501    };
502    run_test(buff, 1, pat1, 4);
503 
504    printf("\n----- Invalid 3rd char AND output exhausted -----\n");
505    /* The character is invalid in its 3rd byte AND the output buffer is
506       exhausted (4 bytes are needed) */
507    uint8_t pat2[] = {
508       0xf0, 0xaa, 0x00, 0x80
509    };
510    run_test(buff, 3, pat2, 4);
511 
512    printf("\n----- Invalid 4th char AND output exhausted -----\n");
513    /* The character is invalid in its 4th byte AND the output buffer is
514       exhausted (4 bytes are needed) */
515    uint8_t pat3[] = {
516       0xf0, 0xaa, 0xaa, 0x00
517    };
518    run_test(buff, 3, pat3, 4);
519 
520    printf("\n----- 1st char valid, 2nd char invalid -----\n");
521    uint8_t valid_invalid[] = {
522       0xf0, 0xaa, 0xaa, 0xaa, // valid
523       0xf0, 0x00, 0x00, 0x00  // invalid
524    };
525    run_test(buff, sizeof buff, valid_invalid, sizeof valid_invalid);
526 }
527 
528 
main()529 int main()
530 {
531    convert_1_byte();
532    convert_2_bytes();
533    convert_3_bytes();
534    convert_4_bytes();
535 
536    /* Length == 0, no memory should be read or written */
537    printf("\n------------- test1 ----------------\n");
538    run_test(NULL, 0, NULL, 0);
539 
540    /* Test exhaustion of source length (source bytes are valid) */
541    printf("\n------------- test2.1 ----------------\n");
542 
543    /* No character will be written to BUFF, i.e. loop in jitted code
544       is not iterated */
545    run_test(buff, sizeof buff, NULL,     0);
546    run_test(buff, sizeof buff, pattern1, 0);
547    run_test(buff, sizeof buff, pattern2, 0);
548    run_test(buff, sizeof buff, pattern2, 1);
549    run_test(buff, sizeof buff, pattern3, 0);
550    run_test(buff, sizeof buff, pattern3, 1);
551    run_test(buff, sizeof buff, pattern3, 2);
552    run_test(buff, sizeof buff, pattern4, 0);
553    run_test(buff, sizeof buff, pattern4, 1);
554    run_test(buff, sizeof buff, pattern4, 2);
555    run_test(buff, sizeof buff, pattern4, 3);
556 
557    printf("\n------------- test2.2 ----------------\n");
558    /* At least one character will be written to BUFF, i.e. loop in jitted
559       code is iterated */
560    run_test(buff, sizeof buff, pattern1, 2);
561    run_test(buff, sizeof buff, pattern2, 5);
562    run_test(buff, sizeof buff, pattern3, 6);
563    run_test(buff, sizeof buff, pattern4, 9);
564 
565    /* Test exhaustion of destination length (source bytes are valid) */
566    printf("\n------------- test3.1 ----------------\n");
567 
568    /* No character will be written to BUFF, i.e. loop in jitted code
569       is not iterated */
570 
571    /* Want to write 2 or 4 bytes at a time */
572    run_test(NULL, 0, pattern1, sizeof pattern1);  // 2-byte result
573    run_test(NULL, 0, pattern2, sizeof pattern2);  // 2-byte result
574    run_test(NULL, 1, pattern2, sizeof pattern2);  // 2-byte result
575    run_test(NULL, 0, pattern3, sizeof pattern3);  // 2-byte result
576    run_test(NULL, 1, pattern3, sizeof pattern3);  // 2-byte result
577    run_test(NULL, 0, pattern4, sizeof pattern4);  // 4-byte result
578    run_test(NULL, 1, pattern4, sizeof pattern4);  // 4-byte result
579    run_test(NULL, 2, pattern4, sizeof pattern4);  // 4-byte result
580    run_test(NULL, 3, pattern4, sizeof pattern4);  // 4-byte result
581 
582    printf("\n------------- test3.2 ----------------\n");
583    /* At least one character will be written to BUFF, i.e. loop in jitted
584       code is iterated */
585    run_test(buff, 4, pattern1, sizeof pattern1);
586    run_test(buff, 5, pattern1, sizeof pattern2);
587    run_test(buff, 6, pattern1, sizeof pattern3);
588    run_test(buff, 7, pattern1, sizeof pattern4);
589 
590    /* Convert buffer with mixed characters */
591    printf("\n------------- test4 ----------------\n");
592    run_test(buff, sizeof buff, mixed, sizeof mixed);
593 
594    return 0;
595 }
596