Merge branch 'nasm-2.03.x'
[platform/upstream/nasm.git] / strfunc.c
1 /*
2  * strfunc.c
3  *
4  * String transformation functions
5  */
6
7 #include "nasmlib.h"
8 #include "nasm.h"
9
10 /*
11  * Convert a string in UTF-8 format to UTF-16LE
12  */
13 static size_t utf8_to_16le(uint8_t *str, size_t len, char *op)
14 {
15 #define EMIT(x) do { if (op) { WRITESHORT(op,x); } outlen++; } while(0)
16
17     size_t outlen = 0;
18     int expect = 0;
19     uint8_t c;
20     uint32_t v = 0, vmin = 0;
21
22     while (len--) {
23         c = *str++;
24
25         if (expect) {
26             if ((c & 0xc0) != 0x80) {
27                 expect = 0;
28                 return -1;
29             } else {
30                 v = (v << 6) | (c & 0x3f);
31                 if (!--expect) {
32                     if (v < vmin || v > 0x10ffff ||
33                         (v >= 0xd800 && v <= 0xdfff)) {
34                         return -1;
35                     } else if (v > 0xffff) {
36                         v -= 0x10000;
37                         EMIT(0xd800 | (v >> 10));
38                         EMIT(0xdc00 | (v & 0x3ff));
39                     } else {
40                         EMIT(v);
41                     }
42                 }
43                 continue;
44             }
45         }
46
47         if (c < 0x80) {
48             EMIT(c);
49         } else if (c < 0xc0 || c >= 0xfe) {
50             /* Invalid UTF-8 */
51             return -1;
52         } else if (c < 0xe0) {
53             v = c & 0x1f;
54             expect = 1;
55             vmin = 0x80;
56         } else if (c < 0xf0) {
57             v = c & 0x0f;
58             expect = 2;
59             vmin = 0x800;
60         } else if (c < 0xf8) {
61             v = c & 0x07;
62             expect = 3;
63             vmin = 0x10000;
64         } else if (c < 0xfc) {
65             v = c & 0x03;
66             expect = 4;
67             vmin = 0x200000;
68         } else {
69             v = c & 0x01;
70             expect = 5;
71             vmin = 0x4000000;
72         }
73     }
74
75     return expect ? (size_t)-1 : outlen << 1;
76
77 #undef EMIT
78 }
79
80 /*
81  * Convert a string in UTF-8 format to UTF-32LE
82  */
83 static size_t utf8_to_32le(uint8_t *str, size_t len, char *op)
84 {
85 #define EMIT(x) do { if (op) { WRITELONG(op,x); } outlen++; } while(0)
86
87     size_t outlen = 0;
88     int expect = 0;
89     uint8_t c;
90     uint32_t v = 0, vmin = 0;
91
92     while (len--) {
93         c = *str++;
94
95         if (expect) {
96             if ((c & 0xc0) != 0x80) {
97                 return -1;
98             } else {
99                 v = (v << 6) | (c & 0x3f);
100                 if (!--expect) {
101                     if (v < vmin || (v >= 0xd800 && v <= 0xdfff)) {
102                         return -1;
103                     } else {
104                         EMIT(v);
105                     }
106                 }
107                 continue;
108             }
109         }
110
111         if (c < 0x80) {
112             EMIT(c);
113         } else if (c < 0xc0 || c >= 0xfe) {
114             /* Invalid UTF-8 */
115             return -1;
116         } else if (c < 0xe0) {
117             v = c & 0x1f;
118             expect = 1;
119             vmin = 0x80;
120         } else if (c < 0xf0) {
121             v = c & 0x0f;
122             expect = 2;
123             vmin = 0x800;
124         } else if (c < 0xf8) {
125             v = c & 0x07;
126             expect = 3;
127             vmin = 0x10000;
128         } else if (c < 0xfc) {
129             v = c & 0x03;
130             expect = 4;
131             vmin = 0x200000;
132         } else {
133             v = c & 0x01;
134             expect = 5;
135             vmin = 0x4000000;
136         }
137     }
138
139     return expect ? (size_t)-1 : outlen << 2;
140
141 #undef EMIT
142 }
143
144 typedef size_t (*transform_func)(uint8_t *, size_t, char *);
145
146 /*
147  * Apply a specific string transform and return it in a nasm_malloc'd
148  * buffer, returning the length.  On error, returns (size_t)-1 and no
149  * buffer is allocated.
150  */
151 size_t string_transform(char *str, size_t len, char **out, enum strfunc func)
152 {
153     /* This should match enum strfunc in nasm.h */
154     static const transform_func str_transforms[] = {
155         utf8_to_16le,
156         utf8_to_32le,
157     };
158     transform_func transform = str_transforms[func];
159     size_t outlen;
160     uint8_t *s = (uint8_t *)str;
161     char *buf;
162
163     outlen = transform(s, len, NULL);
164     if (outlen == (size_t)-1)
165         return -1;
166
167     *out = buf = nasm_malloc(outlen+1);
168     buf[outlen] = '\0';         /* Forcibly null-terminate the buffer */
169     return transform(s, len, buf);
170 }