File Coverage

houdini/houdini_xml_e.c
Criterion Covered Total %
statement 14 25 56.0
branch 11 28 39.2
condition n/a
subroutine n/a
pod n/a
total 25 53 47.1


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4              
5             #include "houdini.h"
6              
7             /**
8             * & --> &
9             * < --> <
10             * > --> >
11             * " --> "
12             * ' --> '
13             */
14             static const char *LOOKUP_CODES[] = {
15             "", /* reserved: use literal single character */
16             "", /* unused */
17             "", /* reserved: 2 character UTF-8 */
18             "", /* reserved: 3 character UTF-8 */
19             "", /* reserved: 4 character UTF-8 */
20             "?", /* invalid UTF-8 character */
21             """,
22             "&",
23             "'",
24             "<",
25             ">"
26             };
27              
28             static const char CODE_INVALID = 5;
29              
30             static const char XML_LOOKUP_TABLE[] = {
31             /* ASCII: 0xxxxxxx */
32             5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 5, 5, 0, 5, 5,
33             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
34             0, 0, 6, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0,
35             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,10, 0,
36             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
38             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
39             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40              
41             /* Invalid UTF-8 char start: 10xxxxxx */
42             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
43             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
44             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
45             5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
46              
47             /* Multibyte UTF-8 */
48              
49             /* 2 bytes: 110xxxxx */
50             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
51             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
52              
53             /* 3 bytes: 1110xxxx */
54             3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
55              
56             /* 4 bytes: 11110xxx */
57             4, 4, 4, 4, 4, 4, 4, 4,
58              
59             /* Invalid UTF-8: 11111xxx */
60             5, 5, 5, 5, 5, 5, 5, 5,
61             };
62              
63             int
64 3           houdini_escape_xml(gh_buf *ob, const uint8_t *src, size_t size)
65             {
66             size_t i = 0;
67             unsigned char code = 0;
68              
69 3           gh_buf_grow(ob, HOUDINI_ESCAPED_SIZE(size));
70              
71 7 100         while (i < size) {
72             size_t start, end;
73              
74             start = end = i;
75              
76 22 100         while (i < size) {
77             unsigned int byte;
78              
79 21           byte = src[i++];
80 21           code = XML_LOOKUP_TABLE[byte];
81              
82 21 100         if (!code) {
83             /* single character used literally */
84 4 50         } else if (code >= CODE_INVALID) {
85             break; /* insert lookup code string */
86 0 0         } else if (code > size - end) {
87             code = CODE_INVALID; /* truncated UTF-8 character */
88             break;
89             } else {
90 0           unsigned int chr = byte & (0xff >> code);
91              
92 0 0         while (--code) {
93 0           byte = src[i++];
94 0 0         if ((byte & 0xc0) != 0x80) {
95             code = CODE_INVALID;
96             break;
97             }
98 0           chr = (chr << 6) + (byte & 0x3f);
99             }
100              
101 0           switch (i - end) {
102             case 2:
103 0 0         if (chr < 0x80)
104             code = CODE_INVALID;
105             break;
106             case 3:
107 0 0         if (chr < 0x800 ||
108 0 0         (chr > 0xd7ff && chr < 0xe000) ||
109             chr > 0xfffd)
110             code = CODE_INVALID;
111             break;
112             case 4:
113 0 0         if (chr < 0x10000 || chr > 0x10ffff)
114             code = CODE_INVALID;
115             break;
116             default:
117             break;
118             }
119 5 0         if (code == CODE_INVALID)
120             break;
121             }
122             end = i;
123             }
124              
125 5 100         if (end > start)
126 3           gh_buf_put(ob, src + start, end - start);
127              
128             /* escaping */
129 5 100         if (end >= size)
130             break;
131              
132 4           gh_buf_puts(ob, LOOKUP_CODES[code]);
133             }
134              
135 3           return 1;
136             }