1965977c3facb05dc36068fdc5cdfaaac4630f40eflorian#include <stdint.h>
2965977c3facb05dc36068fdc5cdfaaac4630f40eflorian#include <inttypes.h>
3965977c3facb05dc36068fdc5cdfaaac4630f40eflorian#include <stdlib.h>
4965977c3facb05dc36068fdc5cdfaaac4630f40eflorian#include <string.h>
5965977c3facb05dc36068fdc5cdfaaac4630f40eflorian#include <stdio.h>
6965977c3facb05dc36068fdc5cdfaaac4630f40eflorian#include "opcodes.h"
7965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
8965977c3facb05dc36068fdc5cdfaaac4630f40eflorian#ifndef M3
9965977c3facb05dc36068fdc5cdfaaac4630f40eflorian#define M3 0
10965977c3facb05dc36068fdc5cdfaaac4630f40eflorian#endif
11965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
12965977c3facb05dc36068fdc5cdfaaac4630f40eflorian/* The abstracted result of an CU12 insn */
13965977c3facb05dc36068fdc5cdfaaac4630f40efloriantypedef struct {
14965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint64_t addr1;  // target
15965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint64_t len1;
16965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint64_t addr2;  // source
17965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint64_t len2;
18965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint32_t cc;
19965977c3facb05dc36068fdc5cdfaaac4630f40eflorian} cu12_t;
20965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
21965977c3facb05dc36068fdc5cdfaaac4630f40eflorian/* Define various input buffers. */
22965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
23965977c3facb05dc36068fdc5cdfaaac4630f40eflorian/* 1-byte UTF-8 character */
24965977c3facb05dc36068fdc5cdfaaac4630f40eflorianuint8_t pattern1[] = {
25965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0x00, 0x01, 0x02, 0x03
26965977c3facb05dc36068fdc5cdfaaac4630f40eflorian};
27965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
28965977c3facb05dc36068fdc5cdfaaac4630f40eflorian/* 2-byte UTF-8 character */
29965977c3facb05dc36068fdc5cdfaaac4630f40eflorianuint8_t pattern2[] = {
30965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xc2, 0x80,
31965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xc2, 0x81,
32965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xc2, 0x82,
33965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xc2, 0x83,
34965977c3facb05dc36068fdc5cdfaaac4630f40eflorian};
35965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
36965977c3facb05dc36068fdc5cdfaaac4630f40eflorian/* 3-byte UTF-8 character */
37965977c3facb05dc36068fdc5cdfaaac4630f40eflorianuint8_t pattern3[] = {
38965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xe1, 0x80, 0x80,
39965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xe1, 0x80, 0x81,
40965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xe1, 0x80, 0x82,
41965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xe1, 0x80, 0x83,
42965977c3facb05dc36068fdc5cdfaaac4630f40eflorian};
43965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
44965977c3facb05dc36068fdc5cdfaaac4630f40eflorian/* 4-byte UTF-8 character */
45965977c3facb05dc36068fdc5cdfaaac4630f40eflorianuint8_t pattern4[] = {
46965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xf4, 0x80, 0x80, 0x80,
47965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xf4, 0x80, 0x80, 0x81,
48965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xf4, 0x80, 0x80, 0x82,
49965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xf4, 0x80, 0x80, 0x83,
50965977c3facb05dc36068fdc5cdfaaac4630f40eflorian};
51965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
52965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
53965977c3facb05dc36068fdc5cdfaaac4630f40eflorian/* Mixed bytes */
54965977c3facb05dc36068fdc5cdfaaac4630f40eflorianuint8_t mixed[] = {
55965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0x01,                    // 1 byte
56965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xc3, 0x80,              // 2 bytes
57965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0x12,                    // 1 byte
58965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xe1, 0x90, 0x93,        // 3 bytes
59965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0x23,                    // 1 byte
60965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xf4, 0x80, 0x90, 0x8a,  // 4 bytes
61965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0x34,                    // 1 byte
62965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xc4, 0x8c,              // 2 bytes
63965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xe1, 0x91, 0x94,        // 3 bytes
64965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xc5, 0x8a,              // 2 bytes
65965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xf4, 0x80, 0x90, 0x8a,  // 4 bytes
66965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xc5, 0x8a,              // 2 bytes
67965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xe1, 0x91, 0x94,        // 3 bytes
68965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xf4, 0x80, 0x90, 0x8a,  // 4 bytes
69965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   0xe1, 0x91, 0x94,        // 3 bytes
70965977c3facb05dc36068fdc5cdfaaac4630f40eflorian};
71965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
72965977c3facb05dc36068fdc5cdfaaac4630f40eflorian/* This is the buffer for the converted bytes. */
73965977c3facb05dc36068fdc5cdfaaac4630f40eflorianuint16_t buff[1000];  /* Large so we con'don't have to worry about it */
74965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
75965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
76965977c3facb05dc36068fdc5cdfaaac4630f40eflorianstatic cu12_t
77965977c3facb05dc36068fdc5cdfaaac4630f40efloriando_cu12(uint16_t *dst, uint64_t dst_len, uint8_t *src, uint64_t src_len)
78965977c3facb05dc36068fdc5cdfaaac4630f40eflorian{
79965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   int cc = 42;
80965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   cu12_t regs;
81965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
82965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* build up the register pairs */
83965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   register uint8_t  *source     asm("4") = src;
84965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   register uint64_t  source_len asm("5") = src_len;
85965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   register uint16_t *dest       asm("2") = dst;
86965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   register uint64_t  dest_len   asm("3") = dst_len;
87965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
88965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   asm volatile(
89965977c3facb05dc36068fdc5cdfaaac4630f40eflorian                CU12(M3,2,4)
90965977c3facb05dc36068fdc5cdfaaac4630f40eflorian                "ipm %2\n\t"
91965977c3facb05dc36068fdc5cdfaaac4630f40eflorian                "srl %2,28\n\t"
92965977c3facb05dc36068fdc5cdfaaac4630f40eflorian                : "+d"(dest), "+d"(source), "=d"(cc),
93965977c3facb05dc36068fdc5cdfaaac4630f40eflorian                  "+d"(source_len), "+d"(dest_len)
94965977c3facb05dc36068fdc5cdfaaac4630f40eflorian                :
95965977c3facb05dc36068fdc5cdfaaac4630f40eflorian                : "memory", "cc");
96965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
97965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* Capture register contents at end of cu12 */
98965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   regs.addr1 = (uint64_t)dest;
99965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   regs.len1  = dest_len;
100965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   regs.addr2 = (uint64_t)source;
101965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   regs.len2  = source_len;
102965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   regs.cc = cc;
103965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
104965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   return regs;
105965977c3facb05dc36068fdc5cdfaaac4630f40eflorian}
106965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
107965977c3facb05dc36068fdc5cdfaaac4630f40eflorianvoid
108965977c3facb05dc36068fdc5cdfaaac4630f40eflorianrun_test(uint16_t *dst, uint64_t dst_len, uint8_t *src, uint64_t src_len)
109965977c3facb05dc36068fdc5cdfaaac4630f40eflorian{
110965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   int i;
111965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   cu12_t result;
112965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
113965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("UTF8:  ");
114965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   if (src_len == 0)
115965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      printf(" <none>");
116965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   else {
117965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      for(i = 0; i < src_len; ++i)
118965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         printf(" %02x", src[i]);
119965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   }
120965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n");
121965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
122965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   result = do_cu12(dst, dst_len, src, src_len);
123965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
124965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // Write out the converted byte, if any
125965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("UTF16: ");
126965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   if (dst_len - result.len1 == 0)
127965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      printf(" <none>");
128965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   else {
129965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint64_t num_bytes = dst_len - result.len1;
130965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
131965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      /* The number of bytes that were written must be divisible by 2 */
132965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      if (num_bytes % 2 != 0)
133965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         fprintf(stderr, "*** number of bytes is not a multiple of 2\n");
134965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
135965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      for (i = 0; i < num_bytes / 2; i++) {
136965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         printf(" %04x", dst[i]);
137965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      }
138965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   }
139965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n");
140965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
141965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("  cc = %d\n", result.cc);
142965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   if (dst != NULL)
143965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      printf("  dst address difference: %"PRId64, result.addr1 - (uint64_t)dst);
144965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("  dst len: %"PRId64"\n", result.len1);
145965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
146965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   if (src != NULL)
147965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      printf("  src address difference: %"PRId64, result.addr2 - (uint64_t)src);
148965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("  src len: %"PRId64"\n", result.len2);
149965977c3facb05dc36068fdc5cdfaaac4630f40eflorian}
150965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
151965977c3facb05dc36068fdc5cdfaaac4630f40eflorian// Test conversion of a one-byte character
152965977c3facb05dc36068fdc5cdfaaac4630f40eflorianvoid convert_1_byte(void)
153965977c3facb05dc36068fdc5cdfaaac4630f40eflorian{
154965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   int i;
155965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
156965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("===== Conversion of a one-byte character =====\n");
157965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
158965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Valid characters -----\n");
159965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t valid[] = {
160965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0x00, 0x7f,              // corner cases
161965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0x01, 0x10, 0x7e, 0x5d   // misc
162965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
163965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, valid, sizeof valid);
164965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
165965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // As conversion stops upon encountering an invalid character, we
166965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // need to test each invalid character separately, to make sure it
167965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // is recognized as invalid.
168965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
169965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid characters -----\n");
170965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t always_invalid[] = {
171965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0x80, 0xbf,              // corner cases
172965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xf8, 0xff,              // corner cases
173965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0x81, 0xbe, 0x95, 0xab   // misc
174965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
175965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   for (i = 0; i < sizeof always_invalid; ++i) {
176965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t invalid_char[1];
177965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      invalid_char[0] = always_invalid[i];
178965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, invalid_char, sizeof invalid_char);
179965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   }
180965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
181965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // In case of m3 == 0 we get cc=0 indicating exhaustion of source
182965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid characters if m3 == 1 -----\n");
183965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t invalid_if_m3[] = {  // contains all such invalid characters
184965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc0, 0xc1,
185965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xf5, 0xf6, 0xf7
186965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
187965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   for (i = 0; i < sizeof invalid_if_m3; ++i) {
188965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t invalid_char[1];
189965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      invalid_char[0] = invalid_if_m3[i];
190965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, invalid_char, sizeof invalid_char);
191965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   }
192965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
193965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- 1st char valid, 2nd char invalid -----\n");
194965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t valid_invalid[] = {
195965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0x10, // valid
196965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xaa  // invalid
197965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
198965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, valid_invalid, sizeof valid_invalid);
199965977c3facb05dc36068fdc5cdfaaac4630f40eflorian}
200965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
201965977c3facb05dc36068fdc5cdfaaac4630f40eflorian// Test conversion of a two-byte character
202965977c3facb05dc36068fdc5cdfaaac4630f40eflorianvoid convert_2_bytes(void)
203965977c3facb05dc36068fdc5cdfaaac4630f40eflorian{
204965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   int i;
205965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
206965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n===== Conversion of a two-byte character =====\n");
207965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
208965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Valid characters -----\n");
209965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t valid[] = {
210965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc2, 0x80,             // corner case
211965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc2, 0xbf,             // corner case
212965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xdf, 0x80,             // corner case
213965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xdf, 0xbf,             // corner case
214965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc3, 0xbe, 0xda, 0xbc  // misc
215965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
216965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, valid, sizeof valid);
217965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
218965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Valid characters if m3 == 0 -----\n");
219965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // First char is 0xc0 or 0xc1
220965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t valid_if_not_m3[] = {
221965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc0, 0x80,
222965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc0, 0xbf,
223965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc1, 0x80,
224965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc0, 0xbf
225965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
226965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, valid_if_not_m3, sizeof valid_if_not_m3);
227965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
228965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // Test for invalid two-byte characters where the 1st byte is valid
229965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // The 2nd byte is invalid if not in range 0x80..0xbf, inclusive
230965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
231965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // As conversion stops upon encountering an invalid character, we
232965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // need to test each invalid character separately, to make sure it
233965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // is recognized as invalid.
234965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
235965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid characters if m3 == 1 -----\n");
236965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t always_invalid[] = {
237965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc2, 0x00,
238965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc2, 0x7f,
239965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc2, 0xc0,
240965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc2, 0xff
241965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
242965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   for (i = 0; i < sizeof always_invalid; i += 2) {
243965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t invalid_char[2];
244965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      invalid_char[0] = always_invalid[i];
245965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      invalid_char[1] = always_invalid[i+1];
246965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, invalid_char, sizeof invalid_char);
247965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   }
248965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
249965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* Nb: for a two-byte character we need not test the case where
250965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      invalidity of the character (cc=2) takes precedence over exhaustion
251965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      of the 1st operand (cc=1). Invalidity of the character has already
252965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      been tested when testing the 1st byte. */
253965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
254965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- 1st char valid, 2nd char invalid -----\n");
255965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t valid_invalid[] = {
256965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc3, 0x81, // valid
257965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xc4, 0x00  // invalid
258965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
259965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, valid_invalid, sizeof valid_invalid);
260965977c3facb05dc36068fdc5cdfaaac4630f40eflorian}
261965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
262965977c3facb05dc36068fdc5cdfaaac4630f40eflorian// Test conversion of a three-byte character
263965977c3facb05dc36068fdc5cdfaaac4630f40eflorianvoid
264965977c3facb05dc36068fdc5cdfaaac4630f40eflorianconvert_3_bytes(void)
265965977c3facb05dc36068fdc5cdfaaac4630f40eflorian{
266965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   int i;
267965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
268965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n===== Conversion of a three-byte character =====\n");
269965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
270965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* Exhaustively test the 1st byte E0 - EF, and the interval boundaries for
271965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      the 2nd and 3rd bytes */
272965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Valid characters -----\n");
273965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t e0[] = {
274965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xe0, 0xa0, 0x80,
275965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xe0, 0xbf, 0x80,
276965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xe0, 0xa0, 0xbf,
277965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xe0, 0xbf, 0xbf,
278965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xe0, 0xaa, 0xbb,   // random  e0 .. ..
279965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
280965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, e0, sizeof e0);
281965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
282965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t ed[] = {
283965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xed, 0x80, 0x80,
284965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xed, 0x9f, 0x80,
285965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xed, 0x80, 0xbf,
286965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xed, 0x9f, 0xbf,
287965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xed, 0x8a, 0xbb,   // random  ed .. ..
288965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
289965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, ed, sizeof ed);
290965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
291965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   for (i = 0; i <= 0xf; ++i) {
292965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t exxx_1[3] = { 0x0, 0x80, 0x80 };
293965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t exxx_2[3] = { 0x0, 0xbf, 0x80 };
294965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t exxx_3[3] = { 0x0, 0x80, 0xbf };
295965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t exxx_4[3] = { 0x0, 0xbf, 0xbf };
296965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
297965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      if (i == 0x00) continue;   // special case e0
298965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      if (i == 0x0d) continue;   // special case ed
299965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
300965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exxx_1[0] = 0xe0 | i;
301965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exxx_2[0] = 0xe0 | i;
302965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exxx_3[0] = 0xe0 | i;
303965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exxx_4[0] = 0xe0 | i;
304965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, exxx_1, sizeof exxx_1);
305965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, exxx_2, sizeof exxx_2);
306965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, exxx_3, sizeof exxx_3);
307965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, exxx_4, sizeof exxx_4);
308965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
309965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
310965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid characters (2nd byte is invalid) -----\n");
311965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // Test for invalid three-byte characters where the 1st byte is valid
312965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // The 2nd byte is invalid.
313965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
314965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // As conversion stops upon encountering an invalid character, we
315965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // need to test each invalid character separately, to make sure it
316965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // is recognized as invalid.
317965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
318965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   e0[0] = 0xe0;  // valid
319965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   e0[1] = 0x9f;  // invalid  because outside [0xa0 .. 0xbf]
320965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   e0[2] = 0x80;  // valid
321965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, e0, sizeof e0);
322965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   e0[1] = 0xc0;  // invalid  because outside [0xa0 .. 0xbf]
323965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, e0, sizeof e0);
324965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
325965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   ed[0] = 0xed;  // valid
326965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   ed[1] = 0x7f;  // invalid  because outside [0x80 .. 0x9f]
327965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   ed[2] = 0x80;  // valid
328965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, ed, sizeof ed);
329965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   ed[1] = 0xa0;  // invalid  because outside [0x80 .. 0x9f]
330965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, ed, sizeof ed);
331965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
332965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   for (i = 0; i <= 0xf; ++i) {
333965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t exxx_1[3] = { 0x0, 0x7f, 0x80 };
334965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t exxx_2[3] = { 0x0, 0xc0, 0x80 };
335965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
336965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      if (i == 0x00) continue;   // special case e0
337965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      if (i == 0x0d) continue;   // special case ed
338965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
339965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exxx_1[0] = 0xe0 | i;
340965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exxx_2[0] = 0xe0 | i;
341965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, exxx_1, sizeof exxx_1);
342965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, exxx_2, sizeof exxx_2);
343965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
344965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
345965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid characters (3rd byte is invalid) -----\n");
346965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // For all 1st bytes 0xe0 .. 0xef the 3rd bytes must be in [0x80 .. 0xbf]
347965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // No need to special case 0xe0 and 0xed
348965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   for (i = 0; i <= 0xf; ++i) {
349965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t exxx_1[3] = { 0x0, 0xab, 0x7f };
350965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t exxx_2[3] = { 0x0, 0xab, 0xc0 };
351965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
352965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exxx_1[0] = 0xe0 | i;
353965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exxx_2[0] = 0xe0 | i;
354965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, exxx_1, sizeof exxx_1);
355965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, exxx_2, sizeof exxx_2);
356965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
357965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
358965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid 2nd char AND output exhausted -----\n");
359965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* The character is invalid in its 2nd byte AND the output buffer is
360965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exhausted (2 bytes are needed) */
361965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t pat1[] = {
362965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xe0, 0x00, 0x80
363965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
364965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, 1, pat1, 3);
365965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
366965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid 3rd char AND output exhausted -----\n");
367965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* The character is invalid in its 3rd byte AND the output buffer is
368965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exhausted (2 bytes are needed) */
369965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t pat2[] = {
370965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xe4, 0x84, 0x00
371965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
372965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, 1, pat2, 3);
373965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
374965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- 1st char valid, 2nd char invalid -----\n");
375965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t valid_invalid[] = {
376965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xe1, 0x90, 0x90, // valid
377965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xe1, 0x00, 0x90  // invalid
378965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
379965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, valid_invalid, sizeof valid_invalid);
380965977c3facb05dc36068fdc5cdfaaac4630f40eflorian}
381965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
382965977c3facb05dc36068fdc5cdfaaac4630f40eflorian// Test conversion of a four-byte character
383965977c3facb05dc36068fdc5cdfaaac4630f40eflorianvoid
384965977c3facb05dc36068fdc5cdfaaac4630f40eflorianconvert_4_bytes(void)
385965977c3facb05dc36068fdc5cdfaaac4630f40eflorian{
386965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   int i, j;
387965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
388965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n===== Conversion of a four-byte character =====\n");
389965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
390965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Valid characters -----\n");
391965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   for (i = 0; i <= 4; ++i) {
392965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t valid[4];
393965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
394965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      valid[0] = 0xf0 | i;
395965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
396965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      for (j = 0; j <= 1; ++j) {
397965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         // Byte 2
398965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         if (i == 0) {
399965977c3facb05dc36068fdc5cdfaaac4630f40eflorian            valid[1] = j == 0 ? 0x90 : 0xbf;    // 0xf0
400965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         } else if (i == 4) {
401965977c3facb05dc36068fdc5cdfaaac4630f40eflorian            valid[1] = j == 0 ? 0x80 : 0x8f;    // 0xf4
402965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         } else {
403965977c3facb05dc36068fdc5cdfaaac4630f40eflorian            valid[1] = j == 0 ? 0x80 : 0xbf;    // 0xf1 .. 0xf3
404965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         }
405965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         // Byte 3 and byte 4 have same interval 0x80 .. 0xbf
406965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         valid[2] = 0x80;
407965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         valid[3] = 0x80;
408965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         run_test(buff, sizeof buff, valid, sizeof valid);
409965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         valid[2] = 0x80;
410965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         valid[3] = 0xbf;
411965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         run_test(buff, sizeof buff, valid, sizeof valid);
412965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         valid[2] = 0xbf;
413965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         valid[3] = 0x80;
414965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         run_test(buff, sizeof buff, valid, sizeof valid);
415965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         valid[2] = 0xbf;
416965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         valid[3] = 0xbf;
417965977c3facb05dc36068fdc5cdfaaac4630f40eflorian         run_test(buff, sizeof buff, valid, sizeof valid);
418965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      }
419965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   }
420965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
421965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Valid characters if m3 == 0 -----\n");
422965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // First char is 0xf5 .. 0xf7
423965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t valid_if_not_m3[] = {
424965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xf5, 0x00, 0x00, 0x00,
425965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xf6, 0x11, 0x22, 0x33,
426965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xf7, 0x44, 0x55, 0x66,
427965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
428965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, valid_if_not_m3, sizeof valid_if_not_m3);
429965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
430965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // As conversion stops upon encountering an invalid character, we
431965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // need to test each invalid character separately, to make sure it
432965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // is recognized as invalid.
433965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
434965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid characters (2nd byte is invalid) -----\n");
435965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // Test for invalid four-byte characters where the 2nd byte is invalid.
436965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // All other bytes are valid
437965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t f0[4], f4[4];
438965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
439965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   f0[0] = 0xf0;  // valid
440965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   f0[1] = 0x8f;  // invalid  because outside [0x90 .. 0xbf]
441965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   f0[2] = 0x80;  // valid
442965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   f0[3] = 0x80;  // valid
443965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, f0, sizeof f0);
444965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   f0[1] = 0xc0;  // invalid  because outside [0x90 .. 0xbf]
445965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, f0, sizeof f0);
446965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
44703129681ef833f5d2461437a48f162dddd4d0c6fflorian   f4[0] = 0xf4;  // valid
448965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   f4[1] = 0x7f;  // invalid  because outside [0x80 .. 0x8f]
449965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   f4[2] = 0x80;  // valid
45003129681ef833f5d2461437a48f162dddd4d0c6fflorian   f4[3] = 0x80;  // valid
451965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, f4, sizeof f4);
452965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   f4[1] = 0x90;  // invalid  because outside [0x80 .. 0x9f]
453965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, f4, sizeof f4);
454965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
455965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   for (i = 0; i <= 0x4; ++i) {
456965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t fxxx_1[4] = { 0x0, 0x7f, 0x80, 0x80 };
457965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t fxxx_2[4] = { 0x0, 0xc0, 0x80, 0x80 };
458965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
459965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      if (i == 0) continue;   // special case f0
460965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      if (i == 4) continue;   // special case f4
461965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
462965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      fxxx_1[0] = 0xf0 | i;
463965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      fxxx_2[0] = 0xf0 | i;
464965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, fxxx_1, sizeof fxxx_1);
465965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, fxxx_2, sizeof fxxx_2);
466965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
467965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
468965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid characters (3rd byte is invalid) -----\n");
469965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // Test for invalid four-byte characters where the 3rd byte is invalid.
470965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // All other bytes are valid
471965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   for (i = 0; i <= 0x4; ++i) {
472965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t fxxx[4] = { 0x0, 0x0, 0x0, 0x80 };
473965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
474965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      fxxx[0] = 0xf0 | i;
475965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      fxxx[1] = (i == 0) ? 0x94 : 0x84;
476965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      fxxx[2] = 0x7f;
477965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, fxxx, sizeof fxxx);
478965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      fxxx[2] = 0xc0;
479965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, fxxx, sizeof fxxx);
480965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
481965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
482965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid characters (4th byte is invalid) -----\n");
483965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // Test for invalid four-byte characters where the 3rd byte is invalid.
484965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   // All other bytes are valid
485965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   for (i = 0; i <= 0x4; ++i) {
486965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      uint8_t fxxx[4] = { 0x0, 0x0, 0x80, 0x0 };
487965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
488965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      fxxx[0] = 0xf0 | i;
489965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      fxxx[1] = (i == 0) ? 0x94 : 0x84;
490965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      fxxx[3] = 0x7f;
491965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, fxxx, sizeof fxxx);
492965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      fxxx[3] = 0xc0;
493965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      run_test(buff, sizeof buff, fxxx, sizeof fxxx);
494965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
495965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
496965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid 2nd char AND output exhausted -----\n");
497965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* The character is invalid in its 2nd byte AND the output buffer is
498965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exhausted (4 bytes are needed) */
499965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t pat1[] = {
500965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xf0, 0x00, 0x80, 0x80
501965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
502965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, 1, pat1, 4);
503965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
504965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid 3rd char AND output exhausted -----\n");
505965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* The character is invalid in its 3rd byte AND the output buffer is
506965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exhausted (4 bytes are needed) */
507965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t pat2[] = {
508965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xf0, 0xaa, 0x00, 0x80
509965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
510965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, 3, pat2, 4);
511965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
512965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- Invalid 4th char AND output exhausted -----\n");
513965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* The character is invalid in its 4th byte AND the output buffer is
514965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      exhausted (4 bytes are needed) */
515965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t pat3[] = {
516965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xf0, 0xaa, 0xaa, 0x00
517965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
518965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, 3, pat3, 4);
519965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
520965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n----- 1st char valid, 2nd char invalid -----\n");
521965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   uint8_t valid_invalid[] = {
522965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xf0, 0xaa, 0xaa, 0xaa, // valid
523965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      0xf0, 0x00, 0x00, 0x00  // invalid
524965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   };
525965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, valid_invalid, sizeof valid_invalid);
526965977c3facb05dc36068fdc5cdfaaac4630f40eflorian}
527965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
528965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
529965977c3facb05dc36068fdc5cdfaaac4630f40eflorianint main()
530965977c3facb05dc36068fdc5cdfaaac4630f40eflorian{
531965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   convert_1_byte();
532965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   convert_2_bytes();
533965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   convert_3_bytes();
534965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   convert_4_bytes();
535965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
536965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* Length == 0, no memory should be read or written */
537965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n------------- test1 ----------------\n");
538965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(NULL, 0, NULL, 0);
539965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
540965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* Test exhaustion of source length (source bytes are valid) */
541965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n------------- test2.1 ----------------\n");
542965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
543965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* No character will be written to BUFF, i.e. loop in jitted code
544965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      is not iterated */
545965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, NULL,     0);
546965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern1, 0);
547965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern2, 0);
548965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern2, 1);
549965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern3, 0);
550965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern3, 1);
551965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern3, 2);
552965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern4, 0);
553965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern4, 1);
554965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern4, 2);
555965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern4, 3);
556965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
557965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n------------- test2.2 ----------------\n");
558965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* At least one character will be written to BUFF, i.e. loop in jitted
559965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      code is iterated */
560965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern1, 2);
561965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern2, 5);
562965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern3, 6);
563965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, pattern4, 9);
564965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
565965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* Test exhaustion of destination length (source bytes are valid) */
566965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n------------- test3.1 ----------------\n");
567965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
568965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* No character will be written to BUFF, i.e. loop in jitted code
569965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      is not iterated */
570965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
571965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* Want to write 2 or 4 bytes at a time */
572965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(NULL, 0, pattern1, sizeof pattern1);  // 2-byte result
573965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(NULL, 0, pattern2, sizeof pattern2);  // 2-byte result
574965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(NULL, 1, pattern2, sizeof pattern2);  // 2-byte result
575965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(NULL, 0, pattern3, sizeof pattern3);  // 2-byte result
576965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(NULL, 1, pattern3, sizeof pattern3);  // 2-byte result
577965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(NULL, 0, pattern4, sizeof pattern4);  // 4-byte result
578965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(NULL, 1, pattern4, sizeof pattern4);  // 4-byte result
579965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(NULL, 2, pattern4, sizeof pattern4);  // 4-byte result
580965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(NULL, 3, pattern4, sizeof pattern4);  // 4-byte result
581965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
582965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n------------- test3.2 ----------------\n");
583965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* At least one character will be written to BUFF, i.e. loop in jitted
584965977c3facb05dc36068fdc5cdfaaac4630f40eflorian      code is iterated */
585965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, 4, pattern1, sizeof pattern1);
586965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, 5, pattern1, sizeof pattern2);
587965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, 6, pattern1, sizeof pattern3);
588965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, 7, pattern1, sizeof pattern4);
589965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
590965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   /* Convert buffer with mixed characters */
591965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   printf("\n------------- test4 ----------------\n");
592965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   run_test(buff, sizeof buff, mixed, sizeof mixed);
593965977c3facb05dc36068fdc5cdfaaac4630f40eflorian
594965977c3facb05dc36068fdc5cdfaaac4630f40eflorian   return 0;
595965977c3facb05dc36068fdc5cdfaaac4630f40eflorian}
596