1use crate::abi::structs::{_xmlNode, xmlChRangeGroup};
30use crate::xml::unicode_tables::*;
31use std::os::raw::{c_int, c_uint, c_ushort};
32
33#[no_mangle]
41pub unsafe extern "C" fn xmlCharInRange(val: c_uint, group: *const xmlChRangeGroup) -> c_int {
42 if group.is_null() {
43 return 0;
44 }
45 let g = unsafe { &*group };
46 if val < 0x10000 {
47 if g.nbShortRange == 0 {
49 return 0;
50 }
51 let mut low = 0;
52 let mut high = g.nbShortRange - 1;
53 let sptr = g.shortRange;
54 if sptr.is_null() {
55 return 0;
56 }
57 while low <= high {
58 let mid = (low + high) / 2;
59 let s = unsafe { &*sptr.add(mid as usize) };
60 if (val as c_ushort) < s.low {
61 high = mid - 1;
62 } else if (val as c_ushort) > s.high {
63 low = mid + 1;
64 } else {
65 return 1;
66 }
67 }
68 0
69 } else {
70 if g.nbLongRange == 0 {
72 return 0;
73 }
74 let mut low = 0;
75 let mut high = g.nbLongRange - 1;
76 let lptr = g.longRange;
77 if lptr.is_null() {
78 return 0;
79 }
80 while low <= high {
81 let mid = (low + high) / 2;
82 let l = unsafe { &*lptr.add(mid as usize) };
83 if val < l.low {
84 high = mid - 1;
85 } else if val > l.high {
86 low = mid + 1;
87 } else {
88 return 1;
89 }
90 }
91 0
92 }
93}
94
95#[inline]
96fn is_base_char_ch(c: c_uint) -> bool {
97 (0x41..=0x5a).contains(&c)
100 || (0x61..=0x7a).contains(&c)
101 || (0xc0..=0xd6).contains(&c)
102 || (0xd8..=0xf6).contains(&c)
103 || c >= 0xf8
104}
105
106#[no_mangle]
108pub unsafe extern "C" fn xmlIsBaseChar(ch: c_uint) -> c_int {
109 if ch < 0x100 {
110 is_base_char_ch(ch) as c_int
111 } else {
112 unsafe { xmlCharInRange(ch, &xmlIsBaseCharGroup) }
113 }
114}
115
116#[no_mangle]
118pub unsafe extern "C" fn xmlIsBlank(ch: c_uint) -> c_int {
119 if ch < 0x100 {
120 (ch == 0x20 || (0x9..=0xa).contains(&ch) || ch == 0xd) as c_int
121 } else {
122 0
123 }
124}
125
126#[no_mangle]
128pub unsafe extern "C" fn xmlIsChar(ch: c_uint) -> c_int {
129 if ch < 0x100 {
130 ((0x9..=0xa).contains(&ch) || ch == 0xd || ch >= 0x20) as c_int
131 } else {
132 ((0x100..=0xd7ff).contains(&ch)
133 || (0xe000..=0xfffd).contains(&ch)
134 || (0x10000..=0x10ffff).contains(&ch)) as c_int
135 }
136}
137
138#[no_mangle]
140pub unsafe extern "C" fn xmlIsCombining(ch: c_uint) -> c_int {
141 if ch < 0x100 {
142 0
143 } else {
144 unsafe { xmlCharInRange(ch, &xmlIsCombiningGroup) }
145 }
146}
147
148#[no_mangle]
150pub unsafe extern "C" fn xmlIsDigit(ch: c_uint) -> c_int {
151 if ch < 0x100 {
152 (0x30..=0x39).contains(&ch) as c_int
153 } else {
154 unsafe { xmlCharInRange(ch, &xmlIsDigitGroup) }
155 }
156}
157
158#[no_mangle]
160pub unsafe extern "C" fn xmlIsExtender(ch: c_uint) -> c_int {
161 if ch < 0x100 {
162 (ch == 0xb7) as c_int
163 } else {
164 unsafe { xmlCharInRange(ch, &xmlIsExtenderGroup) }
165 }
166}
167
168#[no_mangle]
170pub unsafe extern "C" fn xmlIsIdeographic(ch: c_uint) -> c_int {
171 if ch < 0x100 {
172 0
173 } else {
174 ((0x4e00..=0x9fa5).contains(&ch) || ch == 0x3007 || (0x3021..=0x3029).contains(&ch))
175 as c_int
176 }
177}
178
179#[no_mangle]
181pub unsafe extern "C" fn xmlIsPubidChar(ch: c_uint) -> c_int {
182 if ch >= 0x100 {
183 0
184 } else {
185 xmlIsPubidChar_tab[ch as usize] as c_int
186 }
187}
188
189#[no_mangle]
191pub unsafe extern "C" fn xmlIsLetter(c: c_int) -> c_int {
192 let ch = c as c_uint;
193 if ch < 0x100 {
194 is_base_char_ch(ch) as c_int
195 } else {
196 unsafe { xmlIsBaseChar(ch) | xmlIsIdeographic(ch) }
197 }
198}
199
200#[no_mangle]
207pub unsafe extern "C" fn xmlIsBlankNode(node: *const _xmlNode) -> c_int {
208 if node.is_null() {
209 return 0;
210 }
211 let n = unsafe { &*node };
212 if n.type_ != crate::abi::types::xmlElementType::XML_TEXT_NODE as c_int
213 && n.type_ != crate::abi::types::xmlElementType::XML_CDATA_SECTION_NODE as c_int
214 {
215 return 0;
216 }
217 if n.content.is_null() {
218 return 1;
219 }
220 let mut cur = n.content;
221 while !cur.is_null() && *cur != 0 {
222 let ch = *cur as c_uint;
223 if ch != 0x20 && !(0x9..=0xa).contains(&ch) && ch != 0xd {
224 return 0;
225 }
226 cur = cur.add(1);
227 }
228 1
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234 use crate::abi::allocator;
235 use crate::abi::types::xmlChar;
236 use std::os::raw::c_uint;
237
238 fn oracle_is_base_char(ch: c_uint) -> c_int {
241 unsafe { xmlIsBaseChar(ch) }
242 }
243
244 #[test]
245 fn test_xml_is_char_basic() {
246 unsafe {
247 assert_eq!(xmlIsChar(0x9), 1); assert_eq!(xmlIsChar(0xa), 1); assert_eq!(xmlIsChar(0xd), 1); assert_eq!(xmlIsChar(0x20), 1); assert_eq!(xmlIsChar(0x1f), 0); assert_eq!(xmlIsChar(0xd7ff), 1);
254 assert_eq!(xmlIsChar(0xd800), 0); assert_eq!(xmlIsChar(0xe000), 1);
256 assert_eq!(xmlIsChar(0xfffe), 0);
257 assert_eq!(xmlIsChar(0x10000), 1);
258 assert_eq!(xmlIsChar(0x10ffff), 1);
259 assert_eq!(xmlIsChar(0x110000), 0);
260 }
261 }
262
263 #[test]
264 fn test_xml_is_blank() {
265 unsafe {
266 assert_eq!(xmlIsBlank(0x20), 1);
267 assert_eq!(xmlIsBlank(0x9), 1);
268 assert_eq!(xmlIsBlank(0xa), 1);
269 assert_eq!(xmlIsBlank(0xd), 1);
270 assert_eq!(xmlIsBlank(b'x' as c_uint), 0);
271 assert_eq!(xmlIsBlank(0x100), 0);
272 assert_eq!(xmlIsBlank(0x3000), 0); }
274 }
275
276 #[test]
277 fn test_xml_is_base_char_ascii_and_ranges() {
278 unsafe {
279 assert_eq!(xmlIsBaseChar(b'A' as c_uint), 1);
280 assert_eq!(xmlIsBaseChar(b'z' as c_uint), 1);
281 assert_eq!(xmlIsBaseChar(b'0' as c_uint), 0);
282 assert_eq!(xmlIsBaseChar(0xc0), 1); assert_eq!(xmlIsBaseChar(0xd7), 0);
284 assert_eq!(xmlIsBaseChar(0x100), 1); assert_eq!(xmlIsBaseChar(0x132), 0); assert_eq!(xmlIsBaseChar(0x386), 1); assert_eq!(xmlIsBaseChar(0x5d0), 1); assert_eq!(xmlIsBaseChar(0xac00), 1); assert_eq!(xmlIsBaseChar(0xac00), oracle_is_base_char(0xac00));
290 assert_eq!(xmlIsBaseChar(0x2a8), 1);
291 assert_eq!(xmlIsBaseChar(0x2a9), 0);
292 }
293 }
294
295 #[test]
296 fn test_xml_is_digit() {
297 unsafe {
298 assert_eq!(xmlIsDigit(b'0' as c_uint), 1);
299 assert_eq!(xmlIsDigit(b'9' as c_uint), 1);
300 assert_eq!(xmlIsDigit(b'a' as c_uint), 0);
301 assert_eq!(xmlIsDigit(0x660), 1); assert_eq!(xmlIsDigit(0x6f9), 1);
303 assert_eq!(xmlIsDigit(0x670), 0);
304 }
305 }
306
307 #[test]
308 fn test_xml_is_combining_extender_ideographic() {
309 unsafe {
310 assert_eq!(xmlIsCombining(0x300), 1); assert_eq!(xmlIsCombining(0x20,), 0);
312 assert_eq!(xmlIsExtender(0xb7), 1); assert_eq!(xmlIsExtender(0x2d0), 1);
314 assert_eq!(xmlIsExtender(0x3005), 1);
315 assert_eq!(xmlIsExtender(0x20), 0);
316 assert_eq!(xmlIsIdeographic(0x4e00), 1); assert_eq!(xmlIsIdeographic(0x3007), 1);
318 assert_eq!(xmlIsIdeographic(0x3029), 1);
319 assert_eq!(xmlIsIdeographic(0x302a), 0);
320 assert_eq!(xmlIsIdeographic(0x9fa5), 1);
321 assert_eq!(xmlIsIdeographic(b'A' as c_uint), 0);
322 }
323 }
324
325 #[test]
326 fn test_xml_is_pubid_char() {
327 unsafe {
328 assert_eq!(xmlIsPubidChar(b'a' as c_uint), 1);
329 assert_eq!(xmlIsPubidChar(b' ' as c_uint), 1);
330 assert_eq!(xmlIsPubidChar(b'!' as c_uint), 1);
331 assert_eq!(xmlIsPubidChar(b'@' as c_uint), 1);
333 assert_eq!(xmlIsPubidChar(b'^' as c_uint), 0);
335 assert_eq!(xmlIsPubidChar(b'~' as c_uint), 0);
336 assert_eq!(xmlIsPubidChar(0x80), 0);
337 assert_eq!(xmlIsPubidChar(0x100), 0);
338 assert_eq!(xmlIsPubidChar(0x9), 0);
340 }
341 }
342
343 #[test]
344 fn test_xml_is_letter() {
345 unsafe {
346 assert_eq!(xmlIsLetter(b'A' as c_int), 1);
347 assert_eq!(xmlIsLetter(0x4e00), 1); assert_eq!(xmlIsLetter(b'0' as c_int), 0);
349 assert_eq!(xmlIsLetter(0x386), 1);
350 }
351 }
352
353 #[test]
354 fn test_xml_char_in_range_null_group() {
355 unsafe {
356 assert_eq!(xmlCharInRange(0x41, core::ptr::null()), 0);
357 }
358 }
359
360 #[test]
361 fn test_xml_is_blank_node() {
362 unsafe {
363 use crate::abi::types::xmlElementType::*;
364 assert_eq!(xmlIsBlankNode(core::ptr::null()), 0);
366 let node = allocator::xmlMalloc(core::mem::size_of::<_xmlNode>()) as *mut _xmlNode;
368 assert!(!node.is_null());
369 core::ptr::write(
370 node,
371 _xmlNode {
372 type_: XML_TEXT_NODE as c_int,
373 content: core::ptr::null_mut(),
374 ..core::mem::zeroed()
375 },
376 );
377 assert_eq!(xmlIsBlankNode(node), 1);
378 let ws = b" \t\n\r\0" as *const u8 as *mut xmlChar;
380 (*node).content = ws;
381 assert_eq!(xmlIsBlankNode(node), 1);
382 let nw = b" x\0" as *const u8 as *mut xmlChar;
384 (*node).content = nw;
385 assert_eq!(xmlIsBlankNode(node), 0);
386 (*node).type_ = XML_ELEMENT_NODE as c_int;
388 assert_eq!(xmlIsBlankNode(node), 0);
389 allocator::xmlFree(node as *mut libc::c_void);
390 }
391 }
392}