1use rupg_common::SqlState;
4
5use super::{parse_xml_decl, print_xml_decl};
6use crate::TypeError;
7
8const NAME_FIRST: &[(u32, u32)] = &[
10 (0x003A, 0x003A),
11 (0x0041, 0x005A),
12 (0x005F, 0x005F),
13 (0x0061, 0x007A),
14 (0x00C0, 0x00D6),
15 (0x00D8, 0x00F6),
16 (0x00F8, 0x0131),
17 (0x0134, 0x013E),
18 (0x0141, 0x0148),
19 (0x014A, 0x017E),
20 (0x0180, 0x01C3),
21 (0x01CD, 0x01F0),
22 (0x01F4, 0x01F5),
23 (0x01FA, 0x0217),
24 (0x0250, 0x02A8),
25 (0x02BB, 0x02C1),
26 (0x0386, 0x0386),
27 (0x0388, 0x038A),
28 (0x038C, 0x038C),
29 (0x038E, 0x03A1),
30 (0x03A3, 0x03CE),
31 (0x03D0, 0x03D6),
32 (0x03DA, 0x03DA),
33 (0x03DC, 0x03DC),
34 (0x03DE, 0x03DE),
35 (0x03E0, 0x03E0),
36 (0x03E2, 0x03F3),
37 (0x0401, 0x040C),
38 (0x040E, 0x044F),
39 (0x0451, 0x045C),
40 (0x045E, 0x0481),
41 (0x0490, 0x04C4),
42 (0x04C7, 0x04C8),
43 (0x04CB, 0x04CC),
44 (0x04D0, 0x04EB),
45 (0x04EE, 0x04F5),
46 (0x04F8, 0x04F9),
47 (0x0531, 0x0556),
48 (0x0559, 0x0559),
49 (0x0561, 0x0586),
50 (0x05D0, 0x05EA),
51 (0x05F0, 0x05F2),
52 (0x0621, 0x063A),
53 (0x0641, 0x064A),
54 (0x0671, 0x06B7),
55 (0x06BA, 0x06BE),
56 (0x06C0, 0x06CE),
57 (0x06D0, 0x06D3),
58 (0x06D5, 0x06D5),
59 (0x06E5, 0x06E6),
60 (0x0905, 0x0939),
61 (0x093D, 0x093D),
62 (0x0958, 0x0961),
63 (0x0985, 0x098C),
64 (0x098F, 0x0990),
65 (0x0993, 0x09A8),
66 (0x09AA, 0x09B0),
67 (0x09B2, 0x09B2),
68 (0x09B6, 0x09B9),
69 (0x09DC, 0x09DD),
70 (0x09DF, 0x09E1),
71 (0x09F0, 0x09F1),
72 (0x0A05, 0x0A0A),
73 (0x0A0F, 0x0A10),
74 (0x0A13, 0x0A28),
75 (0x0A2A, 0x0A30),
76 (0x0A32, 0x0A33),
77 (0x0A35, 0x0A36),
78 (0x0A38, 0x0A39),
79 (0x0A59, 0x0A5C),
80 (0x0A5E, 0x0A5E),
81 (0x0A72, 0x0A74),
82 (0x0A85, 0x0A8B),
83 (0x0A8D, 0x0A8D),
84 (0x0A8F, 0x0A91),
85 (0x0A93, 0x0AA8),
86 (0x0AAA, 0x0AB0),
87 (0x0AB2, 0x0AB3),
88 (0x0AB5, 0x0AB9),
89 (0x0ABD, 0x0ABD),
90 (0x0AE0, 0x0AE0),
91 (0x0B05, 0x0B0C),
92 (0x0B0F, 0x0B10),
93 (0x0B13, 0x0B28),
94 (0x0B2A, 0x0B30),
95 (0x0B32, 0x0B33),
96 (0x0B36, 0x0B39),
97 (0x0B3D, 0x0B3D),
98 (0x0B5C, 0x0B5D),
99 (0x0B5F, 0x0B61),
100 (0x0B85, 0x0B8A),
101 (0x0B8E, 0x0B90),
102 (0x0B92, 0x0B95),
103 (0x0B99, 0x0B9A),
104 (0x0B9C, 0x0B9C),
105 (0x0B9E, 0x0B9F),
106 (0x0BA3, 0x0BA4),
107 (0x0BA8, 0x0BAA),
108 (0x0BAE, 0x0BB5),
109 (0x0BB7, 0x0BB9),
110 (0x0C05, 0x0C0C),
111 (0x0C0E, 0x0C10),
112 (0x0C12, 0x0C28),
113 (0x0C2A, 0x0C33),
114 (0x0C35, 0x0C39),
115 (0x0C60, 0x0C61),
116 (0x0C85, 0x0C8C),
117 (0x0C8E, 0x0C90),
118 (0x0C92, 0x0CA8),
119 (0x0CAA, 0x0CB3),
120 (0x0CB5, 0x0CB9),
121 (0x0CDE, 0x0CDE),
122 (0x0CE0, 0x0CE1),
123 (0x0D05, 0x0D0C),
124 (0x0D0E, 0x0D10),
125 (0x0D12, 0x0D28),
126 (0x0D2A, 0x0D39),
127 (0x0D60, 0x0D61),
128 (0x0E01, 0x0E2E),
129 (0x0E30, 0x0E30),
130 (0x0E32, 0x0E33),
131 (0x0E40, 0x0E45),
132 (0x0E81, 0x0E82),
133 (0x0E84, 0x0E84),
134 (0x0E87, 0x0E88),
135 (0x0E8A, 0x0E8A),
136 (0x0E8D, 0x0E8D),
137 (0x0E94, 0x0E97),
138 (0x0E99, 0x0E9F),
139 (0x0EA1, 0x0EA3),
140 (0x0EA5, 0x0EA5),
141 (0x0EA7, 0x0EA7),
142 (0x0EAA, 0x0EAB),
143 (0x0EAD, 0x0EAE),
144 (0x0EB0, 0x0EB0),
145 (0x0EB2, 0x0EB3),
146 (0x0EBD, 0x0EBD),
147 (0x0EC0, 0x0EC4),
148 (0x0F40, 0x0F47),
149 (0x0F49, 0x0F69),
150 (0x10A0, 0x10C5),
151 (0x10D0, 0x10F6),
152 (0x1100, 0x1100),
153 (0x1102, 0x1103),
154 (0x1105, 0x1107),
155 (0x1109, 0x1109),
156 (0x110B, 0x110C),
157 (0x110E, 0x1112),
158 (0x113C, 0x113C),
159 (0x113E, 0x113E),
160 (0x1140, 0x1140),
161 (0x114C, 0x114C),
162 (0x114E, 0x114E),
163 (0x1150, 0x1150),
164 (0x1154, 0x1155),
165 (0x1159, 0x1159),
166 (0x115F, 0x1161),
167 (0x1163, 0x1163),
168 (0x1165, 0x1165),
169 (0x1167, 0x1167),
170 (0x1169, 0x1169),
171 (0x116D, 0x116E),
172 (0x1172, 0x1173),
173 (0x1175, 0x1175),
174 (0x119E, 0x119E),
175 (0x11A8, 0x11A8),
176 (0x11AB, 0x11AB),
177 (0x11AE, 0x11AF),
178 (0x11B7, 0x11B8),
179 (0x11BA, 0x11BA),
180 (0x11BC, 0x11C2),
181 (0x11EB, 0x11EB),
182 (0x11F0, 0x11F0),
183 (0x11F9, 0x11F9),
184 (0x1E00, 0x1E9B),
185 (0x1EA0, 0x1EF9),
186 (0x1F00, 0x1F15),
187 (0x1F18, 0x1F1D),
188 (0x1F20, 0x1F45),
189 (0x1F48, 0x1F4D),
190 (0x1F50, 0x1F57),
191 (0x1F59, 0x1F59),
192 (0x1F5B, 0x1F5B),
193 (0x1F5D, 0x1F5D),
194 (0x1F5F, 0x1F7D),
195 (0x1F80, 0x1FB4),
196 (0x1FB6, 0x1FBC),
197 (0x1FBE, 0x1FBE),
198 (0x1FC2, 0x1FC4),
199 (0x1FC6, 0x1FCC),
200 (0x1FD0, 0x1FD3),
201 (0x1FD6, 0x1FDB),
202 (0x1FE0, 0x1FEC),
203 (0x1FF2, 0x1FF4),
204 (0x1FF6, 0x1FFC),
205 (0x2126, 0x2126),
206 (0x212A, 0x212B),
207 (0x212E, 0x212E),
208 (0x2180, 0x2182),
209 (0x3007, 0x3007),
210 (0x3021, 0x3029),
211 (0x3041, 0x3094),
212 (0x30A1, 0x30FA),
213 (0x3105, 0x312C),
214 (0x4E00, 0x9FA5),
215 (0xAC00, 0xD7A3),
216];
217const NAME_CHAR: &[(u32, u32)] = &[
219 (0x002D, 0x002E),
220 (0x0030, 0x003A),
221 (0x0041, 0x005A),
222 (0x005F, 0x005F),
223 (0x0061, 0x007A),
224 (0x00B7, 0x00B7),
225 (0x00C0, 0x00D6),
226 (0x00D8, 0x00F6),
227 (0x00F8, 0x0131),
228 (0x0134, 0x013E),
229 (0x0141, 0x0148),
230 (0x014A, 0x017E),
231 (0x0180, 0x01C3),
232 (0x01CD, 0x01F0),
233 (0x01F4, 0x01F5),
234 (0x01FA, 0x0217),
235 (0x0250, 0x02A8),
236 (0x02BB, 0x02C1),
237 (0x02D0, 0x02D1),
238 (0x0300, 0x0345),
239 (0x0360, 0x0361),
240 (0x0386, 0x038A),
241 (0x038C, 0x038C),
242 (0x038E, 0x03A1),
243 (0x03A3, 0x03CE),
244 (0x03D0, 0x03D6),
245 (0x03DA, 0x03DA),
246 (0x03DC, 0x03DC),
247 (0x03DE, 0x03DE),
248 (0x03E0, 0x03E0),
249 (0x03E2, 0x03F3),
250 (0x0401, 0x040C),
251 (0x040E, 0x044F),
252 (0x0451, 0x045C),
253 (0x045E, 0x0481),
254 (0x0483, 0x0486),
255 (0x0490, 0x04C4),
256 (0x04C7, 0x04C8),
257 (0x04CB, 0x04CC),
258 (0x04D0, 0x04EB),
259 (0x04EE, 0x04F5),
260 (0x04F8, 0x04F9),
261 (0x0531, 0x0556),
262 (0x0559, 0x0559),
263 (0x0561, 0x0586),
264 (0x0591, 0x05A1),
265 (0x05A3, 0x05B9),
266 (0x05BB, 0x05BD),
267 (0x05BF, 0x05BF),
268 (0x05C1, 0x05C2),
269 (0x05C4, 0x05C4),
270 (0x05D0, 0x05EA),
271 (0x05F0, 0x05F2),
272 (0x0621, 0x063A),
273 (0x0640, 0x0652),
274 (0x0660, 0x0669),
275 (0x0670, 0x06B7),
276 (0x06BA, 0x06BE),
277 (0x06C0, 0x06CE),
278 (0x06D0, 0x06D3),
279 (0x06D5, 0x06E8),
280 (0x06EA, 0x06ED),
281 (0x06F0, 0x06F9),
282 (0x0901, 0x0903),
283 (0x0905, 0x0939),
284 (0x093C, 0x094D),
285 (0x0951, 0x0954),
286 (0x0958, 0x0963),
287 (0x0966, 0x096F),
288 (0x0981, 0x0983),
289 (0x0985, 0x098C),
290 (0x098F, 0x0990),
291 (0x0993, 0x09A8),
292 (0x09AA, 0x09B0),
293 (0x09B2, 0x09B2),
294 (0x09B6, 0x09B9),
295 (0x09BC, 0x09BC),
296 (0x09BE, 0x09C4),
297 (0x09C7, 0x09C8),
298 (0x09CB, 0x09CD),
299 (0x09D7, 0x09D7),
300 (0x09DC, 0x09DD),
301 (0x09DF, 0x09E3),
302 (0x09E6, 0x09F1),
303 (0x0A02, 0x0A02),
304 (0x0A05, 0x0A0A),
305 (0x0A0F, 0x0A10),
306 (0x0A13, 0x0A28),
307 (0x0A2A, 0x0A30),
308 (0x0A32, 0x0A33),
309 (0x0A35, 0x0A36),
310 (0x0A38, 0x0A39),
311 (0x0A3C, 0x0A3C),
312 (0x0A3E, 0x0A42),
313 (0x0A47, 0x0A48),
314 (0x0A4B, 0x0A4D),
315 (0x0A59, 0x0A5C),
316 (0x0A5E, 0x0A5E),
317 (0x0A66, 0x0A74),
318 (0x0A81, 0x0A83),
319 (0x0A85, 0x0A8B),
320 (0x0A8D, 0x0A8D),
321 (0x0A8F, 0x0A91),
322 (0x0A93, 0x0AA8),
323 (0x0AAA, 0x0AB0),
324 (0x0AB2, 0x0AB3),
325 (0x0AB5, 0x0AB9),
326 (0x0ABC, 0x0AC5),
327 (0x0AC7, 0x0AC9),
328 (0x0ACB, 0x0ACD),
329 (0x0AE0, 0x0AE0),
330 (0x0AE6, 0x0AEF),
331 (0x0B01, 0x0B03),
332 (0x0B05, 0x0B0C),
333 (0x0B0F, 0x0B10),
334 (0x0B13, 0x0B28),
335 (0x0B2A, 0x0B30),
336 (0x0B32, 0x0B33),
337 (0x0B36, 0x0B39),
338 (0x0B3C, 0x0B43),
339 (0x0B47, 0x0B48),
340 (0x0B4B, 0x0B4D),
341 (0x0B56, 0x0B57),
342 (0x0B5C, 0x0B5D),
343 (0x0B5F, 0x0B61),
344 (0x0B66, 0x0B6F),
345 (0x0B82, 0x0B83),
346 (0x0B85, 0x0B8A),
347 (0x0B8E, 0x0B90),
348 (0x0B92, 0x0B95),
349 (0x0B99, 0x0B9A),
350 (0x0B9C, 0x0B9C),
351 (0x0B9E, 0x0B9F),
352 (0x0BA3, 0x0BA4),
353 (0x0BA8, 0x0BAA),
354 (0x0BAE, 0x0BB5),
355 (0x0BB7, 0x0BB9),
356 (0x0BBE, 0x0BC2),
357 (0x0BC6, 0x0BC8),
358 (0x0BCA, 0x0BCD),
359 (0x0BD7, 0x0BD7),
360 (0x0BE7, 0x0BEF),
361 (0x0C01, 0x0C03),
362 (0x0C05, 0x0C0C),
363 (0x0C0E, 0x0C10),
364 (0x0C12, 0x0C28),
365 (0x0C2A, 0x0C33),
366 (0x0C35, 0x0C39),
367 (0x0C3E, 0x0C44),
368 (0x0C46, 0x0C48),
369 (0x0C4A, 0x0C4D),
370 (0x0C55, 0x0C56),
371 (0x0C60, 0x0C61),
372 (0x0C66, 0x0C6F),
373 (0x0C82, 0x0C83),
374 (0x0C85, 0x0C8C),
375 (0x0C8E, 0x0C90),
376 (0x0C92, 0x0CA8),
377 (0x0CAA, 0x0CB3),
378 (0x0CB5, 0x0CB9),
379 (0x0CBE, 0x0CC4),
380 (0x0CC6, 0x0CC8),
381 (0x0CCA, 0x0CCD),
382 (0x0CD5, 0x0CD6),
383 (0x0CDE, 0x0CDE),
384 (0x0CE0, 0x0CE1),
385 (0x0CE6, 0x0CEF),
386 (0x0D02, 0x0D03),
387 (0x0D05, 0x0D0C),
388 (0x0D0E, 0x0D10),
389 (0x0D12, 0x0D28),
390 (0x0D2A, 0x0D39),
391 (0x0D3E, 0x0D43),
392 (0x0D46, 0x0D48),
393 (0x0D4A, 0x0D4D),
394 (0x0D57, 0x0D57),
395 (0x0D60, 0x0D61),
396 (0x0D66, 0x0D6F),
397 (0x0E01, 0x0E2E),
398 (0x0E30, 0x0E3A),
399 (0x0E40, 0x0E4E),
400 (0x0E50, 0x0E59),
401 (0x0E81, 0x0E82),
402 (0x0E84, 0x0E84),
403 (0x0E87, 0x0E88),
404 (0x0E8A, 0x0E8A),
405 (0x0E8D, 0x0E8D),
406 (0x0E94, 0x0E97),
407 (0x0E99, 0x0E9F),
408 (0x0EA1, 0x0EA3),
409 (0x0EA5, 0x0EA5),
410 (0x0EA7, 0x0EA7),
411 (0x0EAA, 0x0EAB),
412 (0x0EAD, 0x0EAE),
413 (0x0EB0, 0x0EB9),
414 (0x0EBB, 0x0EBD),
415 (0x0EC0, 0x0EC4),
416 (0x0EC6, 0x0EC6),
417 (0x0EC8, 0x0ECD),
418 (0x0ED0, 0x0ED9),
419 (0x0F18, 0x0F19),
420 (0x0F20, 0x0F29),
421 (0x0F35, 0x0F35),
422 (0x0F37, 0x0F37),
423 (0x0F39, 0x0F39),
424 (0x0F3E, 0x0F47),
425 (0x0F49, 0x0F69),
426 (0x0F71, 0x0F84),
427 (0x0F86, 0x0F8B),
428 (0x0F90, 0x0F95),
429 (0x0F97, 0x0F97),
430 (0x0F99, 0x0FAD),
431 (0x0FB1, 0x0FB7),
432 (0x0FB9, 0x0FB9),
433 (0x10A0, 0x10C5),
434 (0x10D0, 0x10F6),
435 (0x1100, 0x1100),
436 (0x1102, 0x1103),
437 (0x1105, 0x1107),
438 (0x1109, 0x1109),
439 (0x110B, 0x110C),
440 (0x110E, 0x1112),
441 (0x113C, 0x113C),
442 (0x113E, 0x113E),
443 (0x1140, 0x1140),
444 (0x114C, 0x114C),
445 (0x114E, 0x114E),
446 (0x1150, 0x1150),
447 (0x1154, 0x1155),
448 (0x1159, 0x1159),
449 (0x115F, 0x1161),
450 (0x1163, 0x1163),
451 (0x1165, 0x1165),
452 (0x1167, 0x1167),
453 (0x1169, 0x1169),
454 (0x116D, 0x116E),
455 (0x1172, 0x1173),
456 (0x1175, 0x1175),
457 (0x119E, 0x119E),
458 (0x11A8, 0x11A8),
459 (0x11AB, 0x11AB),
460 (0x11AE, 0x11AF),
461 (0x11B7, 0x11B8),
462 (0x11BA, 0x11BA),
463 (0x11BC, 0x11C2),
464 (0x11EB, 0x11EB),
465 (0x11F0, 0x11F0),
466 (0x11F9, 0x11F9),
467 (0x1E00, 0x1E9B),
468 (0x1EA0, 0x1EF9),
469 (0x1F00, 0x1F15),
470 (0x1F18, 0x1F1D),
471 (0x1F20, 0x1F45),
472 (0x1F48, 0x1F4D),
473 (0x1F50, 0x1F57),
474 (0x1F59, 0x1F59),
475 (0x1F5B, 0x1F5B),
476 (0x1F5D, 0x1F5D),
477 (0x1F5F, 0x1F7D),
478 (0x1F80, 0x1FB4),
479 (0x1FB6, 0x1FBC),
480 (0x1FBE, 0x1FBE),
481 (0x1FC2, 0x1FC4),
482 (0x1FC6, 0x1FCC),
483 (0x1FD0, 0x1FD3),
484 (0x1FD6, 0x1FDB),
485 (0x1FE0, 0x1FEC),
486 (0x1FF2, 0x1FF4),
487 (0x1FF6, 0x1FFC),
488 (0x20D0, 0x20DC),
489 (0x20E1, 0x20E1),
490 (0x2126, 0x2126),
491 (0x212A, 0x212B),
492 (0x212E, 0x212E),
493 (0x2180, 0x2182),
494 (0x3005, 0x3005),
495 (0x3007, 0x3007),
496 (0x3021, 0x302F),
497 (0x3031, 0x3035),
498 (0x3041, 0x3094),
499 (0x3099, 0x309A),
500 (0x309D, 0x309E),
501 (0x30A1, 0x30FA),
502 (0x30FC, 0x30FE),
503 (0x3105, 0x312C),
504 (0x4E00, 0x9FA5),
505 (0xAC00, 0xD7A3),
506];
507
508fn in_table(table: &[(u32, u32)], c: u32) -> bool {
510 table
511 .binary_search_by(|&(lo, hi)| {
512 if hi < c {
513 std::cmp::Ordering::Less
514 } else if lo > c {
515 std::cmp::Ordering::Greater
516 } else {
517 std::cmp::Ordering::Equal
518 }
519 })
520 .is_ok()
521}
522
523#[must_use]
525pub fn xml_name(ident: &str, fully_escaped: bool, escape_period: bool) -> String {
526 let mut out = String::with_capacity(ident.len());
527 let mut chars = ident.char_indices().peekable();
528 while let Some((i, c)) = chars.next() {
529 let first = i == 0;
530 let next = chars.peek().map(|&(_, n)| n);
531 if c == ':' && (first || fully_escaped) {
532 out.push_str("_x003A_");
533 } else if c == '_' && next == Some('x') {
534 out.push_str("_x005F_");
535 } else if fully_escaped
536 && first
537 && ident.get(..3).is_some_and(|p| p.eq_ignore_ascii_case("xml"))
538 {
539 out.push_str(if c == 'x' { "_x0078_" } else { "_x0058_" });
540 } else if escape_period && c == '.' {
541 out.push_str("_x002E_");
542 } else {
543 let table = if first { NAME_FIRST } else { NAME_CHAR };
544 if in_table(table, u32::from(c)) {
545 out.push(c);
546 } else {
547 out.push_str(&format!("_x{:04X}_", u32::from(c)));
548 }
549 }
550 }
551 out
552}
553
554#[must_use]
556pub fn sql_name(name: &str) -> String {
557 let bytes = name.as_bytes();
558 let mut out = String::with_capacity(name.len());
559 let mut i = 0;
560 while i < bytes.len() {
561 let escape = bytes.get(i..i + 7).filter(|w| {
562 w[0] == b'_'
563 && w[1] == b'x'
564 && w[2..6].iter().all(u8::is_ascii_hexdigit)
565 && w[6] == b'_'
566 });
567 if let Some(w) = escape {
568 let hex = std::str::from_utf8(&w[2..6]).unwrap_or("0");
569 let code = u32::from_str_radix(hex, 16).unwrap_or(0);
570 out.push(char::from_u32(code).unwrap_or(char::REPLACEMENT_CHARACTER));
571 i += 7;
572 } else {
573 let len = name[i..].chars().next().map_or(1, char::len_utf8);
574 out.push_str(&name[i..i + len]);
575 i += len;
576 }
577 }
578 out
579}
580
581#[must_use]
583pub fn escape_xml(text: &str) -> String {
584 let mut out = String::with_capacity(text.len());
585 for c in text.chars() {
586 match c {
587 '&' => out.push_str("&"),
588 '<' => out.push_str("<"),
589 '>' => out.push_str(">"),
590 '\r' => out.push_str("
"),
591 _ => out.push(c),
592 }
593 }
594 out
595}
596
597#[must_use]
599pub fn xml_text(text: &str) -> String {
600 let mut out = String::with_capacity(text.len());
601 for c in text.chars() {
602 match c {
603 '&' => out.push_str("&"),
604 '<' => out.push_str("<"),
605 '>' => out.push_str(">"),
606 '"' => out.push_str("""),
607 '\r' => out.push_str(" "),
608 _ => out.push(c),
609 }
610 }
611 out
612}
613
614fn attribute_value(text: &str, out: &mut String) {
616 for c in text.chars() {
617 match c {
618 '\n' => out.push_str(" "),
619 '\r' => out.push_str(" "),
620 '\t' => out.push_str("	"),
621 '"' => out.push_str("""),
622 '<' => out.push_str("<"),
623 '>' => out.push_str(">"),
624 '&' => out.push_str("&"),
625 c if u32::from(c) < 0x20 => {}
626 c if c.is_ascii() => out.push(c),
627 c => out.push_str(&format!("&#x{:X};", u32::from(c))),
628 }
629 }
630}
631
632#[must_use]
634pub fn xml_element(name: &str, attributes: &[(&str, &str)], content: &[String]) -> String {
635 let mut out = String::new();
636 out.push('<');
637 out.push_str(name);
638 for (attr, value) in attributes {
639 out.push(' ');
640 out.push_str(attr);
641 out.push_str("=\"");
642 attribute_value(value, &mut out);
643 out.push('"');
644 }
645 if content.is_empty() {
646 out.push_str("/>");
647 } else {
648 out.push('>');
649 for part in content {
650 out.push_str(part);
651 }
652 out.push_str("</");
653 out.push_str(name);
654 out.push('>');
655 }
656 out
657}
658
659#[must_use]
661pub fn xml_concat(values: &[&str]) -> String {
662 let mut standalone_all = 1;
663 let mut version_all: Option<&[u8]> = None;
664 let mut no_version = false;
665 let mut body = Vec::new();
666 for value in values {
667 let bytes = value.as_bytes();
668 let (len, version, standalone) = match parse_xml_decl(bytes) {
669 Ok(decl) => (decl.len, decl.version, decl.standalone),
670 Err(_) => (0, None, -1),
671 };
672 if standalone == 0 && standalone_all == 1 {
673 standalone_all = 0;
674 }
675 if standalone < 0 {
676 standalone_all = -1;
677 }
678 match (version, version_all) {
679 (None, _) => no_version = true,
680 (Some(v), None) => version_all = Some(v),
681 (Some(v), Some(all)) if v != all => no_version = true,
682 _ => {}
683 }
684 body.extend_from_slice(&bytes[len..]);
685 }
686 let mut out = Vec::new();
687 if !no_version || standalone_all >= 0 {
688 print_xml_decl(&mut out, if no_version { None } else { version_all }, standalone_all);
689 }
690 out.extend_from_slice(&body);
691 String::from_utf8(out).unwrap_or_default()
692}
693
694#[derive(Clone, Copy, Debug, PartialEq, Eq)]
696pub enum XmlStandalone {
697 Yes,
698 No,
699 NoValue,
700 Omitted,
702}
703
704#[must_use]
706pub fn xml_root(data: &str, version: Option<&str>, standalone: XmlStandalone) -> String {
707 let bytes = data.as_bytes();
708 let (len, old) = match parse_xml_decl(bytes) {
709 Ok(decl) => (decl.len, decl.standalone),
710 Err(_) => (0, -1),
711 };
712 let standalone = match standalone {
713 XmlStandalone::Yes => 1,
714 XmlStandalone::No => 0,
715 XmlStandalone::NoValue => -1,
716 XmlStandalone::Omitted => old,
717 };
718 let mut out = Vec::new();
719 print_xml_decl(&mut out, version.map(str::as_bytes), standalone);
720 out.extend_from_slice(&bytes[len..]);
721 String::from_utf8(out).unwrap_or_default()
722}
723
724fn invalid_pi(detail: String) -> TypeError {
726 let mut error = TypeError::new(
727 SqlState::INVALID_XML_PROCESSING_INSTRUCTION,
728 "invalid XML processing instruction".to_string(),
729 );
730 error.detail = Some(detail);
731 error
732}
733
734pub fn xml_pi(target: &str, arg: Option<&str>, null: bool) -> Result<Option<String>, TypeError> {
740 if target.eq_ignore_ascii_case("xml") {
741 return Err(invalid_pi(format!(
742 "XML processing instruction target name cannot be \"{target}\"."
743 )));
744 }
745 if null {
746 return Ok(None);
747 }
748 let mut out = format!("<?{target}");
749 if let Some(arg) = arg {
750 if arg.contains("?>") {
751 return Err(invalid_pi(
752 "XML processing instruction cannot contain \"?>\".".to_string(),
753 ));
754 }
755 out.push(' ');
756 out.push_str(arg.trim_start_matches(' '));
757 }
758 out.push_str("?>");
759 Ok(Some(out))
760}
761
762pub fn xml_comment(text: &str) -> Result<String, TypeError> {
768 if text.contains("--") || text.ends_with('-') {
769 return Err(TypeError::new(
770 SqlState::INVALID_XML_COMMENT,
771 "invalid XML comment".to_string(),
772 ));
773 }
774 Ok(format!("<!--{text}-->"))
775}
776
777#[must_use]
779pub fn xml_base64(bytes: &[u8]) -> String {
780 const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
781 let mut out = String::with_capacity(bytes.len() * 4 / 3 + 4);
782 let mut line = 0;
783 for chunk in bytes.chunks(3) {
784 if line >= 72 {
785 out.push_str("\r\n");
786 line = 0;
787 }
788 let b = [chunk[0], chunk.get(1).copied().unwrap_or(0), chunk.get(2).copied().unwrap_or(0)];
789 let n = u32::from(b[0]) << 16 | u32::from(b[1]) << 8 | u32::from(b[2]);
790 for k in 0..4 {
791 if k <= chunk.len() {
792 out.push(char::from(ALPHABET[((n >> (18 - 6 * k)) & 0x3f) as usize]));
793 } else {
794 out.push('=');
795 }
796 }
797 line += 4;
798 }
799 out
800}
801
802#[must_use]
804pub fn xml_binhex(bytes: &[u8]) -> String {
805 let mut out = String::with_capacity(bytes.len() * 2);
806 for b in bytes {
807 out.push_str(&format!("{b:02X}"));
808 }
809 out
810}
811
812#[cfg(test)]
813mod tests {
814 use super::*;
815
816 #[test]
817 fn names() {
818 assert_eq!(xml_name("a b", false, false), "a_x0020_b");
819 assert_eq!(xml_name(":x", false, false), "_x003A_x");
820 assert_eq!(xml_name("c:d", false, false), "c:d");
821 assert_eq!(xml_name("c:d", true, false), "c_x003A_d");
822 assert_eq!(xml_name("_x", false, false), "_x005F_x");
823 assert_eq!(xml_name("1a", false, false), "_x0031_a");
824 assert_eq!(xml_name("xmlfoo", false, false), "xmlfoo");
825 assert_eq!(xml_name("XmLfoo", true, false), "_x0058_mLfoo");
826 assert_eq!(xml_name("a.b", true, true), "a_x002E_b");
827 assert_eq!(xml_name("\u{e9}", false, false), "\u{e9}");
828 assert_eq!(xml_name("\u{101d0}", false, false), "_x101D0_");
829 assert_eq!(sql_name("a_x0020_b"), "a b");
830 assert_eq!(sql_name("_x005F_x"), "_x");
831 assert_eq!(sql_name("_x00"), "_x00");
832 }
833
834 #[test]
835 fn text() {
836 assert_eq!(escape_xml("<&>\r\"'"), "<&>
\"'");
837 assert_eq!(xml_text("<a & b>\r\""), "<a & b> "");
838 assert_eq!(xml_element("a", &[], &[]), "<a/>");
839 assert_eq!(xml_element("a", &[], &[String::new()]), "<a></a>");
840 assert_eq!(
841 xml_element("a", &[("b", "<\"\r\n\t'\u{e9}\u{1}")], &["x".to_string()]),
842 "<a b=\"<" 	'é\">x</a>"
843 );
844 }
845
846 #[test]
847 fn declarations() {
848 assert_eq!(xml_concat(&["<a/>", "<b/>"]), "<a/><b/>");
849 assert_eq!(
850 xml_concat(&[
851 "<?xml version=\"1.1\"?><a/>",
852 "<?xml version=\"1.1\" standalone=\"no\"?><b/>"
853 ]),
854 "<?xml version=\"1.1\"?><a/><b/>"
855 );
856 assert_eq!(
857 xml_concat(&["<?xml version=\"1.0\" standalone=\"yes\"?><a/>", "<b/>"]),
858 "<a/><b/>"
859 );
860 assert_eq!(
861 xml_root("<a/>", Some("1.1"), XmlStandalone::Omitted),
862 "<?xml version=\"1.1\"?><a/>"
863 );
864 assert_eq!(
865 xml_root(
866 "<?xml version=\"1.1\" standalone=\"yes\"?><a/>",
867 None,
868 XmlStandalone::Omitted
869 ),
870 "<?xml version=\"1.0\" standalone=\"yes\"?><a/>"
871 );
872 assert_eq!(xml_root("<a/>", Some("1.0"), XmlStandalone::NoValue), "<a/>");
873 }
874
875 #[test]
876 fn others() {
877 assert_eq!(xml_pi("foo", Some(" bar"), false).unwrap().as_deref(), Some("<?foo bar?>"));
878 assert_eq!(xml_pi("foo", None, true).unwrap(), None);
879 assert!(xml_pi("XmL", None, true).is_err());
880 assert!(xml_pi("foo", Some("a?>"), false).is_err());
881 assert_eq!(xml_comment("a-b").unwrap(), "<!--a-b-->");
882 assert!(xml_comment("a--b").is_err());
883 assert!(xml_comment("a-").is_err());
884 assert_eq!(xml_base64(&[0xab]), "qw==");
885 assert_eq!(xml_base64(&[0xab, 0xcd]), "q80=");
886 assert_eq!(xml_base64(&[0xab; 54]).len(), 72);
887 assert_eq!(&xml_base64(&[0xab; 55])[72..], "\r\nqw==");
888 assert_eq!(xml_binhex(&[1, 2, 0xff]), "0102FF");
889 }
890}