1/**
2 * pugixml parser - version 1.2
3 * --------------------------------------------------------
4 * Copyright (C) 2006-2012, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
5 * Report bugs and download new versions at http://pugixml.org/
6 *
7 * This library is distributed under the MIT License. See notice at the end
8 * of this file.
9 *
10 * This work is based on the pugxml parser, which is:
11 * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
12 */
13
14#ifndef SOURCE_PUGIXML_CPP
15#define SOURCE_PUGIXML_CPP
16
17#include "pugixml.hpp"
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
22#include <assert.h>
23#include <wchar.h>
24
25#ifndef PUGIXML_NO_XPATH
26# include <math.h>
27# include <float.h>
28# ifdef PUGIXML_NO_EXCEPTIONS
29# include <setjmp.h>
30# endif
31#endif
32
33#ifndef PUGIXML_NO_STL
34# include <istream>
35# include <ostream>
36# include <string>
37#endif
38
39// For placement new
40#include <new>
41
42#ifdef _MSC_VER
43# pragma warning(push)
44# pragma warning(disable: 4127) // conditional expression is constant
45# pragma warning(disable: 4324) // structure was padded due to __declspec(align())
46# pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
47# pragma warning(disable: 4702) // unreachable code
48# pragma warning(disable: 4996) // this function or variable may be unsafe
49# pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
50#endif
51
52#ifdef __INTEL_COMPILER
53# pragma warning(disable: 177) // function was declared but never referenced
54# pragma warning(disable: 279) // controlling expression is constant
55# pragma warning(disable: 1478 1786) // function was declared "deprecated"
56# pragma warning(disable: 1684) // conversion from pointer to same-sized integral type
57#endif
58
59#if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
60# pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away
61#endif
62
63#ifdef __BORLANDC__
64# pragma option push
65# pragma warn -8008 // condition is always false
66# pragma warn -8066 // unreachable code
67#endif
68
69#ifdef __SNC__
70// Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug
71# pragma diag_suppress=178 // function was declared but never referenced
72# pragma diag_suppress=237 // controlling expression is constant
73#endif
74
75// Inlining controls
76#if defined(_MSC_VER) && _MSC_VER >= 1300
77# define PUGI__NO_INLINE __declspec(noinline)
78#elif defined(__GNUC__)
79# define PUGI__NO_INLINE __attribute__((noinline))
80#else
81# define PUGI__NO_INLINE
82#endif
83
84// Simple static assertion
85#define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
86
87// Digital Mars C++ bug workaround for passing char loaded from memory via stack
88#ifdef __DMC__
89# define PUGI__DMC_VOLATILE volatile
90#else
91# define PUGI__DMC_VOLATILE
92#endif
93
94// Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all)
95#if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
96using std::memcpy;
97using std::memmove;
98#endif
99
100// In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features
101#if defined(_MSC_VER) && !defined(__S3E__)
102# define PUGI__MSVC_CRT_VERSION _MSC_VER
103#endif
104
105#ifdef PUGIXML_HEADER_ONLY
106# define PUGI__NS_BEGIN namespace pugi { namespace impl {
107# define PUGI__NS_END } }
108# define PUGI__FN inline
109# define PUGI__FN_NO_INLINE inline
110#else
111# if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
112# define PUGI__NS_BEGIN namespace pugi { namespace impl {
113# define PUGI__NS_END } }
114# else
115# define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace {
116# define PUGI__NS_END } } }
117# endif
118# define PUGI__FN
119# define PUGI__FN_NO_INLINE PUGI__NO_INLINE
120#endif
121
122// uintptr_t
123#if !defined(_MSC_VER) || _MSC_VER >= 1600
124# include <stdint.h>
125#else
126# ifndef _UINTPTR_T_DEFINED
127// No native uintptr_t in MSVC6 and in some WinCE versions
128typedef size_t uintptr_t;
129#define _UINTPTR_T_DEFINED
130# endif
131PUGI__NS_BEGIN
132 typedef unsigned __int8 uint8_t;
133 typedef unsigned __int16 uint16_t;
134 typedef unsigned __int32 uint32_t;
135PUGI__NS_END
136#endif
137
138// Memory allocation
139PUGI__NS_BEGIN
140 PUGI__FN void* default_allocate(size_t size)
141 {
142 return malloc(size);
143 }
144
145 PUGI__FN void default_deallocate(void* ptr)
146 {
147 free(ptr);
148 }
149
150 template <typename T>
151 struct xml_memory_management_function_storage
152 {
153 static allocation_function allocate;
154 static deallocation_function deallocate;
155 };
156
157 template <typename T> allocation_function xml_memory_management_function_storage<T>::allocate = default_allocate;
158 template <typename T> deallocation_function xml_memory_management_function_storage<T>::deallocate = default_deallocate;
159
160 typedef xml_memory_management_function_storage<int> xml_memory;
161PUGI__NS_END
162
163// String utilities
164PUGI__NS_BEGIN
165 // Get string length
166 PUGI__FN size_t strlength(const char_t* s)
167 {
168 assert(s);
169
170 #ifdef PUGIXML_WCHAR_MODE
171 return wcslen(s);
172 #else
173 return strlen(s);
174 #endif
175 }
176
177 // Compare two strings
178 PUGI__FN bool strequal(const char_t* src, const char_t* dst)
179 {
180 assert(src && dst);
181
182 #ifdef PUGIXML_WCHAR_MODE
183 return wcscmp(src, dst) == 0;
184 #else
185 return strcmp(src, dst) == 0;
186 #endif
187 }
188
189 // Compare lhs with [rhs_begin, rhs_end)
190 PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
191 {
192 for (size_t i = 0; i < count; ++i)
193 if (lhs[i] != rhs[i])
194 return false;
195
196 return lhs[count] == 0;
197 }
198
199#ifdef PUGIXML_WCHAR_MODE
200 // Convert string to wide string, assuming all symbols are ASCII
201 PUGI__FN void widen_ascii(wchar_t* dest, const char* source)
202 {
203 for (const char* i = source; *i; ++i) *dest++ = *i;
204 *dest = 0;
205 }
206#endif
207PUGI__NS_END
208
209#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH)
210// auto_ptr-like buffer holder for exception recovery
211PUGI__NS_BEGIN
212 struct buffer_holder
213 {
214 void* data;
215 void (*deleter)(void*);
216
217 buffer_holder(void* data_, void (*deleter_)(void*)): data(data_), deleter(deleter_)
218 {
219 }
220
221 ~buffer_holder()
222 {
223 if (data) deleter(data);
224 }
225
226 void* release()
227 {
228 void* result = data;
229 data = 0;
230 return result;
231 }
232 };
233PUGI__NS_END
234#endif
235
236PUGI__NS_BEGIN
237 static const size_t xml_memory_page_size =
238 #ifdef PUGIXML_MEMORY_PAGE_SIZE
239 PUGIXML_MEMORY_PAGE_SIZE
240 #else
241 32768
242 #endif
243 ;
244
245 static const uintptr_t xml_memory_page_alignment = 32;
246 static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1);
247 static const uintptr_t xml_memory_page_name_allocated_mask = 16;
248 static const uintptr_t xml_memory_page_value_allocated_mask = 8;
249 static const uintptr_t xml_memory_page_type_mask = 7;
250
251 struct xml_allocator;
252
253 struct xml_memory_page
254 {
255 static xml_memory_page* construct(void* memory)
256 {
257 if (!memory) return 0; //$ redundant, left for performance
258
259 xml_memory_page* result = static_cast<xml_memory_page*>(memory);
260
261 result->allocator = 0;
262 result->memory = 0;
263 result->prev = 0;
264 result->next = 0;
265 result->busy_size = 0;
266 result->freed_size = 0;
267
268 return result;
269 }
270
271 xml_allocator* allocator;
272
273 void* memory;
274
275 xml_memory_page* prev;
276 xml_memory_page* next;
277
278 size_t busy_size;
279 size_t freed_size;
280
281 char data[1];
282 };
283
284 struct xml_memory_string_header
285 {
286 uint16_t page_offset; // offset from page->data
287 uint16_t full_size; // 0 if string occupies whole page
288 };
289
290 struct xml_allocator
291 {
292 xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)
293 {
294 }
295
296 xml_memory_page* allocate_page(size_t data_size)
297 {
298 size_t size = offsetof(xml_memory_page, data) + data_size;
299
300 // allocate block with some alignment, leaving memory for worst-case padding
301 void* memory = xml_memory::allocate(size + xml_memory_page_alignment);
302 if (!memory) return 0;
303
304 // align upwards to page boundary
305 void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1));
306
307 // prepare page structure
308 xml_memory_page* page = xml_memory_page::construct(page_memory);
309
310 page->memory = memory;
311 page->allocator = _root->allocator;
312
313 return page;
314 }
315
316 static void deallocate_page(xml_memory_page* page)
317 {
318 xml_memory::deallocate(page->memory);
319 }
320
321 void* allocate_memory_oob(size_t size, xml_memory_page*& out_page);
322
323 void* allocate_memory(size_t size, xml_memory_page*& out_page)
324 {
325 if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page);
326
327 void* buf = _root->data + _busy_size;
328
329 _busy_size += size;
330
331 out_page = _root;
332
333 return buf;
334 }
335
336 void deallocate_memory(void* ptr, size_t size, xml_memory_page* page)
337 {
338 if (page == _root) page->busy_size = _busy_size;
339
340 assert(ptr >= page->data && ptr < page->data + page->busy_size);
341 (void)!ptr;
342
343 page->freed_size += size;
344 assert(page->freed_size <= page->busy_size);
345
346 if (page->freed_size == page->busy_size)
347 {
348 if (page->next == 0)
349 {
350 assert(_root == page);
351
352 // top page freed, just reset sizes
353 page->busy_size = page->freed_size = 0;
354 _busy_size = 0;
355 }
356 else
357 {
358 assert(_root != page);
359 assert(page->prev);
360
361 // remove from the list
362 page->prev->next = page->next;
363 page->next->prev = page->prev;
364
365 // deallocate
366 deallocate_page(page);
367 }
368 }
369 }
370
371 char_t* allocate_string(size_t length)
372 {
373 // allocate memory for string and header block
374 size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
375
376 // round size up to pointer alignment boundary
377 size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1);
378
379 xml_memory_page* page;
380 xml_memory_string_header* header = static_cast<xml_memory_string_header*>(allocate_memory(full_size, page));
381
382 if (!header) return 0;
383
384 // setup header
385 ptrdiff_t page_offset = reinterpret_cast<char*>(header) - page->data;
386
387 assert(page_offset >= 0 && page_offset < (1 << 16));
388 header->page_offset = static_cast<uint16_t>(page_offset);
389
390 // full_size == 0 for large strings that occupy the whole page
391 assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0));
392 header->full_size = static_cast<uint16_t>(full_size < (1 << 16) ? full_size : 0);
393
394 // round-trip through void* to avoid 'cast increases required alignment of target type' warning
395 // header is guaranteed a pointer-sized alignment, which should be enough for char_t
396 return static_cast<char_t*>(static_cast<void*>(header + 1));
397 }
398
399 void deallocate_string(char_t* string)
400 {
401 // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings
402 // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string
403
404 // get header
405 xml_memory_string_header* header = static_cast<xml_memory_string_header*>(static_cast<void*>(string)) - 1;
406
407 // deallocate
408 size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset;
409 xml_memory_page* page = reinterpret_cast<xml_memory_page*>(static_cast<void*>(reinterpret_cast<char*>(header) - page_offset));
410
411 // if full_size == 0 then this string occupies the whole page
412 size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size;
413
414 deallocate_memory(header, full_size, page);
415 }
416
417 xml_memory_page* _root;
418 size_t _busy_size;
419 };
420
421 PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page)
422 {
423 const size_t large_allocation_threshold = xml_memory_page_size / 4;
424
425 xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
426 out_page = page;
427
428 if (!page) return 0;
429
430 if (size <= large_allocation_threshold)
431 {
432 _root->busy_size = _busy_size;
433
434 // insert page at the end of linked list
435 page->prev = _root;
436 _root->next = page;
437 _root = page;
438
439 _busy_size = size;
440 }
441 else
442 {
443 // insert page before the end of linked list, so that it is deleted as soon as possible
444 // the last page is not deleted even if it's empty (see deallocate_memory)
445 assert(_root->prev);
446
447 page->prev = _root->prev;
448 page->next = _root;
449
450 _root->prev->next = page;
451 _root->prev = page;
452 }
453
454 // allocate inside page
455 page->busy_size = size;
456
457 return page->data;
458 }
459PUGI__NS_END
460
461namespace pugi
462{
463 /// A 'name=value' XML attribute structure.
464 struct xml_attribute_struct
465 {
466 /// Default ctor
467 xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0)
468 {
469 }
470
471 uintptr_t header;
472
473 char_t* name; ///< Pointer to attribute name.
474 char_t* value; ///< Pointer to attribute value.
475
476 xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list)
477 xml_attribute_struct* next_attribute; ///< Next attribute
478 };
479
480 /// An XML document tree node.
481 struct xml_node_struct
482 {
483 /// Default ctor
484 /// \param type - node type
485 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast<uintptr_t>(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0)
486 {
487 }
488
489 uintptr_t header;
490
491 xml_node_struct* parent; ///< Pointer to parent
492
493 char_t* name; ///< Pointer to element name.
494 char_t* value; ///< Pointer to any associated string data.
495
496 xml_node_struct* first_child; ///< First child
497
498 xml_node_struct* prev_sibling_c; ///< Left brother (cyclic list)
499 xml_node_struct* next_sibling; ///< Right brother
500
501 xml_attribute_struct* first_attribute; ///< First attribute
502 };
503}
504
505PUGI__NS_BEGIN
506 struct xml_document_struct: public xml_node_struct, public xml_allocator
507 {
508 xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0)
509 {
510 }
511
512 const char_t* buffer;
513 };
514
515 inline xml_allocator& get_allocator(const xml_node_struct* node)
516 {
517 assert(node);
518
519 return *reinterpret_cast<xml_memory_page*>(node->header & xml_memory_page_pointer_mask)->allocator;
520 }
521PUGI__NS_END
522
523// Low-level DOM operations
524PUGI__NS_BEGIN
525 inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc)
526 {
527 xml_memory_page* page;
528 void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page);
529
530 return new (memory) xml_attribute_struct(page);
531 }
532
533 inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type)
534 {
535 xml_memory_page* page;
536 void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page);
537
538 return new (memory) xml_node_struct(page, type);
539 }
540
541 inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc)
542 {
543 uintptr_t header = a->header;
544
545 if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name);
546 if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value);
547
548 alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask));
549 }
550
551 inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
552 {
553 uintptr_t header = n->header;
554
555 if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name);
556 if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value);
557
558 for (xml_attribute_struct* attr = n->first_attribute; attr; )
559 {
560 xml_attribute_struct* next = attr->next_attribute;
561
562 destroy_attribute(attr, alloc);
563
564 attr = next;
565 }
566
567 for (xml_node_struct* child = n->first_child; child; )
568 {
569 xml_node_struct* next = child->next_sibling;
570
571 destroy_node(child, alloc);
572
573 child = next;
574 }
575
576 alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask));
577 }
578
579 PUGI__FN_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
580 {
581 xml_node_struct* child = allocate_node(alloc, type);
582 if (!child) return 0;
583
584 child->parent = node;
585
586 xml_node_struct* first_child = node->first_child;
587
588 if (first_child)
589 {
590 xml_node_struct* last_child = first_child->prev_sibling_c;
591
592 last_child->next_sibling = child;
593 child->prev_sibling_c = last_child;
594 first_child->prev_sibling_c = child;
595 }
596 else
597 {
598 node->first_child = child;
599 child->prev_sibling_c = child;
600 }
601
602 return child;
603 }
604
605 PUGI__FN_NO_INLINE xml_attribute_struct* append_attribute_ll(xml_node_struct* node, xml_allocator& alloc)
606 {
607 xml_attribute_struct* a = allocate_attribute(alloc);
608 if (!a) return 0;
609
610 xml_attribute_struct* first_attribute = node->first_attribute;
611
612 if (first_attribute)
613 {
614 xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c;
615
616 last_attribute->next_attribute = a;
617 a->prev_attribute_c = last_attribute;
618 first_attribute->prev_attribute_c = a;
619 }
620 else
621 {
622 node->first_attribute = a;
623 a->prev_attribute_c = a;
624 }
625
626 return a;
627 }
628PUGI__NS_END
629
630// Helper classes for code generation
631PUGI__NS_BEGIN
632 struct opt_false
633 {
634 enum { value = 0 };
635 };
636
637 struct opt_true
638 {
639 enum { value = 1 };
640 };
641PUGI__NS_END
642
643// Unicode utilities
644PUGI__NS_BEGIN
645 inline uint16_t endian_swap(uint16_t value)
646 {
647 return static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8));
648 }
649
650 inline uint32_t endian_swap(uint32_t value)
651 {
652 return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);
653 }
654
655 struct utf8_counter
656 {
657 typedef size_t value_type;
658
659 static value_type low(value_type result, uint32_t ch)
660 {
661 // U+0000..U+007F
662 if (ch < 0x80) return result + 1;
663 // U+0080..U+07FF
664 else if (ch < 0x800) return result + 2;
665 // U+0800..U+FFFF
666 else return result + 3;
667 }
668
669 static value_type high(value_type result, uint32_t)
670 {
671 // U+10000..U+10FFFF
672 return result + 4;
673 }
674 };
675
676 struct utf8_writer
677 {
678 typedef uint8_t* value_type;
679
680 static value_type low(value_type result, uint32_t ch)
681 {
682 // U+0000..U+007F
683 if (ch < 0x80)
684 {
685 *result = static_cast<uint8_t>(ch);
686 return result + 1;
687 }
688 // U+0080..U+07FF
689 else if (ch < 0x800)
690 {
691 result[0] = static_cast<uint8_t>(0xC0 | (ch >> 6));
692 result[1] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
693 return result + 2;
694 }
695 // U+0800..U+FFFF
696 else
697 {
698 result[0] = static_cast<uint8_t>(0xE0 | (ch >> 12));
699 result[1] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
700 result[2] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
701 return result + 3;
702 }
703 }
704
705 static value_type high(value_type result, uint32_t ch)
706 {
707 // U+10000..U+10FFFF
708 result[0] = static_cast<uint8_t>(0xF0 | (ch >> 18));
709 result[1] = static_cast<uint8_t>(0x80 | ((ch >> 12) & 0x3F));
710 result[2] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
711 result[3] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
712 return result + 4;
713 }
714
715 static value_type any(value_type result, uint32_t ch)
716 {
717 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
718 }
719 };
720
721 struct utf16_counter
722 {
723 typedef size_t value_type;
724
725 static value_type low(value_type result, uint32_t)
726 {
727 return result + 1;
728 }
729
730 static value_type high(value_type result, uint32_t)
731 {
732 return result + 2;
733 }
734 };
735
736 struct utf16_writer
737 {
738 typedef uint16_t* value_type;
739
740 static value_type low(value_type result, uint32_t ch)
741 {
742 *result = static_cast<uint16_t>(ch);
743
744 return result + 1;
745 }
746
747 static value_type high(value_type result, uint32_t ch)
748 {
749 uint32_t msh = static_cast<uint32_t>(ch - 0x10000) >> 10;
750 uint32_t lsh = static_cast<uint32_t>(ch - 0x10000) & 0x3ff;
751
752 result[0] = static_cast<uint16_t>(0xD800 + msh);
753 result[1] = static_cast<uint16_t>(0xDC00 + lsh);
754
755 return result + 2;
756 }
757
758 static value_type any(value_type result, uint32_t ch)
759 {
760 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
761 }
762 };
763
764 struct utf32_counter
765 {
766 typedef size_t value_type;
767
768 static value_type low(value_type result, uint32_t)
769 {
770 return result + 1;
771 }
772
773 static value_type high(value_type result, uint32_t)
774 {
775 return result + 1;
776 }
777 };
778
779 struct utf32_writer
780 {
781 typedef uint32_t* value_type;
782
783 static value_type low(value_type result, uint32_t ch)
784 {
785 *result = ch;
786
787 return result + 1;
788 }
789
790 static value_type high(value_type result, uint32_t ch)
791 {
792 *result = ch;
793
794 return result + 1;
795 }
796
797 static value_type any(value_type result, uint32_t ch)
798 {
799 *result = ch;
800
801 return result + 1;
802 }
803 };
804
805 struct latin1_writer
806 {
807 typedef uint8_t* value_type;
808
809 static value_type low(value_type result, uint32_t ch)
810 {
811 *result = static_cast<uint8_t>(ch > 255 ? '?' : ch);
812
813 return result + 1;
814 }
815
816 static value_type high(value_type result, uint32_t ch)
817 {
818 (void)ch;
819
820 *result = '?';
821
822 return result + 1;
823 }
824 };
825
826 template <size_t size> struct wchar_selector;
827
828 template <> struct wchar_selector<2>
829 {
830 typedef uint16_t type;
831 typedef utf16_counter counter;
832 typedef utf16_writer writer;
833 };
834
835 template <> struct wchar_selector<4>
836 {
837 typedef uint32_t type;
838 typedef utf32_counter counter;
839 typedef utf32_writer writer;
840 };
841
842 typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
843 typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
844
845 template <typename Traits, typename opt_swap = opt_false> struct utf_decoder
846 {
847 static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result)
848 {
849 const uint8_t utf8_byte_mask = 0x3f;
850
851 while (size)
852 {
853 uint8_t lead = *data;
854
855 // 0xxxxxxx -> U+0000..U+007F
856 if (lead < 0x80)
857 {
858 result = Traits::low(result, lead);
859 data += 1;
860 size -= 1;
861
862 // process aligned single-byte (ascii) blocks
863 if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
864 {
865 // round-trip through void* to silence 'cast increases required alignment of target type' warnings
866 while (size >= 4 && (*static_cast<const uint32_t*>(static_cast<const void*>(data)) & 0x80808080) == 0)
867 {
868 result = Traits::low(result, data[0]);
869 result = Traits::low(result, data[1]);
870 result = Traits::low(result, data[2]);
871 result = Traits::low(result, data[3]);
872 data += 4;
873 size -= 4;
874 }
875 }
876 }
877 // 110xxxxx -> U+0080..U+07FF
878 else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
879 {
880 result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
881 data += 2;
882 size -= 2;
883 }
884 // 1110xxxx -> U+0800-U+FFFF
885 else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
886 {
887 result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));
888 data += 3;
889 size -= 3;
890 }
891 // 11110xxx -> U+10000..U+10FFFF
892 else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
893 {
894 result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
895 data += 4;
896 size -= 4;
897 }
898 // 10xxxxxx or 11111xxx -> invalid
899 else
900 {
901 data += 1;
902 size -= 1;
903 }
904 }
905
906 return result;
907 }
908
909 static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result)
910 {
911 const uint16_t* end = data + size;
912
913 while (data < end)
914 {
915 uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
916
917 // U+0000..U+D7FF
918 if (lead < 0xD800)
919 {
920 result = Traits::low(result, lead);
921 data += 1;
922 }
923 // U+E000..U+FFFF
924 else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
925 {
926 result = Traits::low(result, lead);
927 data += 1;
928 }
929 // surrogate pair lead
930 else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && data + 1 < end)
931 {
932 uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
933
934 if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
935 {
936 result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
937 data += 2;
938 }
939 else
940 {
941 data += 1;
942 }
943 }
944 else
945 {
946 data += 1;
947 }
948 }
949
950 return result;
951 }
952
953 static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result)
954 {
955 const uint32_t* end = data + size;
956
957 while (data < end)
958 {
959 uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
960
961 // U+0000..U+FFFF
962 if (lead < 0x10000)
963 {
964 result = Traits::low(result, lead);
965 data += 1;
966 }
967 // U+10000..U+10FFFF
968 else
969 {
970 result = Traits::high(result, lead);
971 data += 1;
972 }
973 }
974
975 return result;
976 }
977
978 static inline typename Traits::value_type decode_latin1_block(const uint8_t* data, size_t size, typename Traits::value_type result)
979 {
980 for (size_t i = 0; i < size; ++i)
981 {
982 result = Traits::low(result, data[i]);
983 }
984
985 return result;
986 }
987
988 static inline typename Traits::value_type decode_wchar_block_impl(const uint16_t* data, size_t size, typename Traits::value_type result)
989 {
990 return decode_utf16_block(data, size, result);
991 }
992
993 static inline typename Traits::value_type decode_wchar_block_impl(const uint32_t* data, size_t size, typename Traits::value_type result)
994 {
995 return decode_utf32_block(data, size, result);
996 }
997
998 static inline typename Traits::value_type decode_wchar_block(const wchar_t* data, size_t size, typename Traits::value_type result)
999 {
1000 return decode_wchar_block_impl(reinterpret_cast<const wchar_selector<sizeof(wchar_t)>::type*>(data), size, result);
1001 }
1002 };
1003
1004 template <typename T> PUGI__FN void convert_utf_endian_swap(T* result, const T* data, size_t length)
1005 {
1006 for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]);
1007 }
1008
1009#ifdef PUGIXML_WCHAR_MODE
1010 PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
1011 {
1012 for (size_t i = 0; i < length; ++i) result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));
1013 }
1014#endif
1015PUGI__NS_END
1016
1017PUGI__NS_BEGIN
1018 enum chartype_t
1019 {
1020 ct_parse_pcdata = 1, // \0, &, \r, <
1021 ct_parse_attr = 2, // \0, &, \r, ', "
1022 ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab
1023 ct_space = 8, // \r, \n, space, tab
1024 ct_parse_cdata = 16, // \0, ], >, \r
1025 ct_parse_comment = 32, // \0, -, >, \r
1026 ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, .
1027 ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, :
1028 };
1029
1030 static const unsigned char chartype_table[256] =
1031 {
1032 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15
1033 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
1034 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47
1035 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63
1036 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79
1037 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95
1038 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111
1039 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127
1040
1041 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+
1042 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1043 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1044 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1045 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1046 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1047 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1048 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192
1049 };
1050
1051 enum chartypex_t
1052 {
1053 ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, >
1054 ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, "
1055 ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _
1056 ctx_digit = 8, // 0-9
1057 ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, .
1058 };
1059
1060 static const unsigned char chartypex_table[256] =
1061 {
1062 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15
1063 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31
1064 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47
1065 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63
1066
1067 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79
1068 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95
1069 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111
1070 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127
1071
1072 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+
1073 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1074 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1075 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1076 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1077 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1078 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1079 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
1080 };
1081
1082#ifdef PUGIXML_WCHAR_MODE
1083 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
1084#else
1085 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
1086#endif
1087
1088 #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
1089 #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
1090
1091 PUGI__FN bool is_little_endian()
1092 {
1093 unsigned int ui = 1;
1094
1095 return *reinterpret_cast<unsigned char*>(&ui) == 1;
1096 }
1097
1098 PUGI__FN xml_encoding get_wchar_encoding()
1099 {
1100 PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
1101
1102 if (sizeof(wchar_t) == 2)
1103 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1104 else
1105 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1106 }
1107
1108 PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
1109 {
1110 // look for BOM in first few bytes
1111 if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be;
1112 if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le;
1113 if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be;
1114 if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le;
1115 if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8;
1116
1117 // look for <, <? or <?xm in various encodings
1118 if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be;
1119 if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le;
1120 if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be;
1121 if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le;
1122 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d) return encoding_utf8;
1123
1124 // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early)
1125 if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be;
1126 if (d0 == 0x3c && d1 == 0) return encoding_utf16_le;
1127
1128 // no known BOM detected, assume utf8
1129 return encoding_utf8;
1130 }
1131
1132 PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)
1133 {
1134 // replace wchar encoding with utf implementation
1135 if (encoding == encoding_wchar) return get_wchar_encoding();
1136
1137 // replace utf16 encoding with utf16 with specific endianness
1138 if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1139
1140 // replace utf32 encoding with utf32 with specific endianness
1141 if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1142
1143 // only do autodetection if no explicit encoding is requested
1144 if (encoding != encoding_auto) return encoding;
1145
1146 // skip encoding autodetection if input buffer is too small
1147 if (size < 4) return encoding_utf8;
1148
1149 // try to guess encoding (based on XML specification, Appendix F.1)
1150 const uint8_t* data = static_cast<const uint8_t*>(contents);
1151
1152 PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
1153
1154 return guess_buffer_encoding(d0, d1, d2, d3);
1155 }
1156
1157 PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
1158 {
1159 if (is_mutable)
1160 {
1161 out_buffer = static_cast<char_t*>(const_cast<void*>(contents));
1162 }
1163 else
1164 {
1165 void* buffer = xml_memory::allocate(size > 0 ? size : 1);
1166 if (!buffer) return false;
1167
1168 memcpy(buffer, contents, size);
1169
1170 out_buffer = static_cast<char_t*>(buffer);
1171 }
1172
1173 out_length = size / sizeof(char_t);
1174
1175 return true;
1176 }
1177
1178#ifdef PUGIXML_WCHAR_MODE
1179 PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
1180 {
1181 return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||
1182 (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
1183 }
1184
1185 PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
1186 {
1187 const char_t* data = static_cast<const char_t*>(contents);
1188
1189 if (is_mutable)
1190 {
1191 out_buffer = const_cast<char_t*>(data);
1192 }
1193 else
1194 {
1195 out_buffer = static_cast<char_t*>(xml_memory::allocate(size > 0 ? size : 1));
1196 if (!out_buffer) return false;
1197 }
1198
1199 out_length = size / sizeof(char_t);
1200
1201 convert_wchar_endian_swap(out_buffer, data, out_length);
1202
1203 return true;
1204 }
1205
1206 PUGI__FN bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size)
1207 {
1208 const uint8_t* data = static_cast<const uint8_t*>(contents);
1209
1210 // first pass: get length in wchar_t units
1211 out_length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
1212
1213 // allocate buffer of suitable length
1214 out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
1215 if (!out_buffer) return false;
1216
1217 // second pass: convert utf8 input to wchar_t
1218 wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
1219 wchar_writer::value_type out_end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, out_begin);
1220
1221 assert(out_end == out_begin + out_length);
1222 (void)!out_end;
1223
1224 return true;
1225 }
1226
1227 template <typename opt_swap> PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
1228 {
1229 const uint16_t* data = static_cast<const uint16_t*>(contents);
1230 size_t length = size / sizeof(uint16_t);
1231
1232 // first pass: get length in wchar_t units
1233 out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf16_block(data, length, 0);
1234
1235 // allocate buffer of suitable length
1236 out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
1237 if (!out_buffer) return false;
1238
1239 // second pass: convert utf16 input to wchar_t
1240 wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
1241 wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf16_block(data, length, out_begin);
1242
1243 assert(out_end == out_begin + out_length);
1244 (void)!out_end;
1245
1246 return true;
1247 }
1248
1249 template <typename opt_swap> PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
1250 {
1251 const uint32_t* data = static_cast<const uint32_t*>(contents);
1252 size_t length = size / sizeof(uint32_t);
1253
1254 // first pass: get length in wchar_t units
1255 out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf32_block(data, length, 0);
1256
1257 // allocate buffer of suitable length
1258 out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
1259 if (!out_buffer) return false;
1260
1261 // second pass: convert utf32 input to wchar_t
1262 wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
1263 wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf32_block(data, length, out_begin);
1264
1265 assert(out_end == out_begin + out_length);
1266 (void)!out_end;
1267
1268 return true;
1269 }
1270
1271 PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size)
1272 {
1273 const uint8_t* data = static_cast<const uint8_t*>(contents);
1274
1275 // get length in wchar_t units
1276 out_length = size;
1277
1278 // allocate buffer of suitable length
1279 out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
1280 if (!out_buffer) return false;
1281
1282 // convert latin1 input to wchar_t
1283 wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
1284 wchar_writer::value_type out_end = utf_decoder<wchar_writer>::decode_latin1_block(data, size, out_begin);
1285
1286 assert(out_end == out_begin + out_length);
1287 (void)!out_end;
1288
1289 return true;
1290 }
1291
1292 PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)
1293 {
1294 // get native encoding
1295 xml_encoding wchar_encoding = get_wchar_encoding();
1296
1297 // fast path: no conversion required
1298 if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1299
1300 // only endian-swapping is required
1301 if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
1302
1303 // source encoding is utf8
1304 if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size);
1305
1306 // source encoding is utf16
1307 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
1308 {
1309 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1310
1311 return (native_encoding == encoding) ?
1312 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
1313 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
1314 }
1315
1316 // source encoding is utf32
1317 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
1318 {
1319 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1320
1321 return (native_encoding == encoding) ?
1322 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
1323 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
1324 }
1325
1326 // source encoding is latin1
1327 if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size);
1328
1329 assert(!"Invalid encoding");
1330 return false;
1331 }
1332#else
1333 template <typename opt_swap> PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
1334 {
1335 const uint16_t* data = static_cast<const uint16_t*>(contents);
1336 size_t length = size / sizeof(uint16_t);
1337
1338 // first pass: get length in utf8 units
1339 out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf16_block(data, length, 0);
1340
1341 // allocate buffer of suitable length
1342 out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
1343 if (!out_buffer) return false;
1344
1345 // second pass: convert utf16 input to utf8
1346 uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer);
1347 uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf16_block(data, length, out_begin);
1348
1349 assert(out_end == out_begin + out_length);
1350 (void)!out_end;
1351
1352 return true;
1353 }
1354
1355 template <typename opt_swap> PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
1356 {
1357 const uint32_t* data = static_cast<const uint32_t*>(contents);
1358 size_t length = size / sizeof(uint32_t);
1359
1360 // first pass: get length in utf8 units
1361 out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf32_block(data, length, 0);
1362
1363 // allocate buffer of suitable length
1364 out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
1365 if (!out_buffer) return false;
1366
1367 // second pass: convert utf32 input to utf8
1368 uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer);
1369 uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf32_block(data, length, out_begin);
1370
1371 assert(out_end == out_begin + out_length);
1372 (void)!out_end;
1373
1374 return true;
1375 }
1376
1377 PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)
1378 {
1379 for (size_t i = 0; i < size; ++i)
1380 if (data[i] > 127)
1381 return i;
1382
1383 return size;
1384 }
1385
1386 PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
1387 {
1388 const uint8_t* data = static_cast<const uint8_t*>(contents);
1389
1390 // get size of prefix that does not need utf8 conversion
1391 size_t prefix_length = get_latin1_7bit_prefix_length(data, size);
1392 assert(prefix_length <= size);
1393
1394 const uint8_t* postfix = data + prefix_length;
1395 size_t postfix_length = size - prefix_length;
1396
1397 // if no conversion is needed, just return the original buffer
1398 if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1399
1400 // first pass: get length in utf8 units
1401 out_length = prefix_length + utf_decoder<utf8_counter>::decode_latin1_block(postfix, postfix_length, 0);
1402
1403 // allocate buffer of suitable length
1404 out_buffer = static_cast<char_t*>(xml_memory::allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
1405 if (!out_buffer) return false;
1406
1407 // second pass: convert latin1 input to utf8
1408 memcpy(out_buffer, data, prefix_length);
1409
1410 uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer);
1411 uint8_t* out_end = utf_decoder<utf8_writer>::decode_latin1_block(postfix, postfix_length, out_begin + prefix_length);
1412
1413 assert(out_end == out_begin + out_length);
1414 (void)!out_end;
1415
1416 return true;
1417 }
1418
1419 PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)
1420 {
1421 // fast path: no conversion required
1422 if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1423
1424 // source encoding is utf16
1425 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
1426 {
1427 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1428
1429 return (native_encoding == encoding) ?
1430 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
1431 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
1432 }
1433
1434 // source encoding is utf32
1435 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
1436 {
1437 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1438
1439 return (native_encoding == encoding) ?
1440 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
1441 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
1442 }
1443
1444 // source encoding is latin1
1445 if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
1446
1447 assert(!"Invalid encoding");
1448 return false;
1449 }
1450#endif
1451
1452 PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length)
1453 {
1454 // get length in utf8 characters
1455 return utf_decoder<utf8_counter>::decode_wchar_block(str, length, 0);
1456 }
1457
1458 PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length)
1459 {
1460 // convert to utf8
1461 uint8_t* begin = reinterpret_cast<uint8_t*>(buffer);
1462 uint8_t* end = utf_decoder<utf8_writer>::decode_wchar_block(str, length, begin);
1463
1464 assert(begin + size == end);
1465 (void)!end;
1466
1467 // zero-terminate
1468 buffer[size] = 0;
1469 }
1470
1471#ifndef PUGIXML_NO_STL
1472 PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length)
1473 {
1474 // first pass: get length in utf8 characters
1475 size_t size = as_utf8_begin(str, length);
1476
1477 // allocate resulting string
1478 std::string result;
1479 result.resize(size);
1480
1481 // second pass: convert to utf8
1482 if (size > 0) as_utf8_end(&result[0], size, str, length);
1483
1484 return result;
1485 }
1486
1487 PUGI__FN std::basic_string<wchar_t> as_wide_impl(const char* str, size_t size)
1488 {
1489 const uint8_t* data = reinterpret_cast<const uint8_t*>(str);
1490
1491 // first pass: get length in wchar_t units
1492 size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
1493
1494 // allocate resulting string
1495 std::basic_string<wchar_t> result;
1496 result.resize(length);
1497
1498 // second pass: convert to wchar_t
1499 if (length > 0)
1500 {
1501 wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]);
1502 wchar_writer::value_type end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, begin);
1503
1504 assert(begin + length == end);
1505 (void)!end;
1506 }
1507
1508 return result;
1509 }
1510#endif
1511
1512 inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target)
1513 {
1514 assert(target);
1515 size_t target_length = strlength(target);
1516
1517 // always reuse document buffer memory if possible
1518 if (!allocated) return target_length >= length;
1519
1520 // reuse heap memory if waste is not too great
1521 const size_t reuse_threshold = 32;
1522
1523 return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2);
1524 }
1525
1526 PUGI__FN bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source)
1527 {
1528 size_t source_length = strlength(source);
1529
1530 if (source_length == 0)
1531 {
1532 // empty string and null pointer are equivalent, so just deallocate old memory
1533 xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator;
1534
1535 if (header & header_mask) alloc->deallocate_string(dest);
1536
1537 // mark the string as not allocated
1538 dest = 0;
1539 header &= ~header_mask;
1540
1541 return true;
1542 }
1543 else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest))
1544 {
1545 // we can reuse old buffer, so just copy the new data (including zero terminator)
1546 memcpy(dest, source, (source_length + 1) * sizeof(char_t));
1547
1548 return true;
1549 }
1550 else
1551 {
1552 xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator;
1553
1554 // allocate new buffer
1555 char_t* buf = alloc->allocate_string(source_length + 1);
1556 if (!buf) return false;
1557
1558 // copy the string (including zero terminator)
1559 memcpy(buf, source, (source_length + 1) * sizeof(char_t));
1560
1561 // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)
1562 if (header & header_mask) alloc->deallocate_string(dest);
1563
1564 // the string is now allocated, so set the flag
1565 dest = buf;
1566 header |= header_mask;
1567
1568 return true;
1569 }
1570 }
1571
1572 struct gap
1573 {
1574 char_t* end;
1575 size_t size;
1576
1577 gap(): end(0), size(0)
1578 {
1579 }
1580
1581 // Push new gap, move s count bytes further (skipping the gap).
1582 // Collapse previous gap.
1583 void push(char_t*& s, size_t count)
1584 {
1585 if (end) // there was a gap already; collapse it
1586 {
1587 // Move [old_gap_end, new_gap_start) to [old_gap_start, ...)
1588 assert(s >= end);
1589 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
1590 }
1591
1592 s += count; // end of current gap
1593
1594 // "merge" two gaps
1595 end = s;
1596 size += count;
1597 }
1598
1599 // Collapse all gaps, return past-the-end pointer
1600 char_t* flush(char_t* s)
1601 {
1602 if (end)
1603 {
1604 // Move [old_gap_end, current_pos) to [old_gap_start, ...)
1605 assert(s >= end);
1606 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
1607
1608 return s - size;
1609 }
1610 else return s;
1611 }
1612 };
1613
1614 PUGI__FN char_t* strconv_escape(char_t* s, gap& g)
1615 {
1616 char_t* stre = s + 1;
1617
1618 switch (*stre)
1619 {
1620 case '#': // &#...
1621 {
1622 unsigned int ucsc = 0;
1623
1624 if (stre[1] == 'x') // &#x... (hex code)
1625 {
1626 stre += 2;
1627
1628 char_t ch = *stre;
1629
1630 if (ch == ';') return stre;
1631
1632 for (;;)
1633 {
1634 if (static_cast<unsigned int>(ch - '0') <= 9)
1635 ucsc = 16 * ucsc + (ch - '0');
1636 else if (static_cast<unsigned int>((ch | ' ') - 'a') <= 5)
1637 ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10);
1638 else if (ch == ';')
1639 break;
1640 else // cancel
1641 return stre;
1642
1643 ch = *++stre;
1644 }
1645
1646 ++stre;
1647 }
1648 else // &#... (dec code)
1649 {
1650 char_t ch = *++stre;
1651
1652 if (ch == ';') return stre;
1653
1654 for (;;)
1655 {
1656 if (static_cast<unsigned int>(ch - '0') <= 9)
1657 ucsc = 10 * ucsc + (ch - '0');
1658 else if (ch == ';')
1659 break;
1660 else // cancel
1661 return stre;
1662
1663 ch = *++stre;
1664 }
1665
1666 ++stre;
1667 }
1668
1669 #ifdef PUGIXML_WCHAR_MODE
1670 s = reinterpret_cast<char_t*>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc));
1671 #else
1672 s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc));
1673 #endif
1674
1675 g.push(s, stre - s);
1676 return stre;
1677 }
1678
1679 case 'a': // &a
1680 {
1681 ++stre;
1682
1683 if (*stre == 'm') // &am
1684 {
1685 if (*++stre == 'p' && *++stre == ';') // &
1686 {
1687 *s++ = '&';
1688 ++stre;
1689
1690 g.push(s, stre - s);
1691 return stre;
1692 }
1693 }
1694 else if (*stre == 'p') // &ap
1695 {
1696 if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // '
1697 {
1698 *s++ = '\'';
1699 ++stre;
1700
1701 g.push(s, stre - s);
1702 return stre;
1703 }
1704 }
1705 break;
1706 }
1707
1708 case 'g': // &g
1709 {
1710 if (*++stre == 't' && *++stre == ';') // >
1711 {
1712 *s++ = '>';
1713 ++stre;
1714
1715 g.push(s, stre - s);
1716 return stre;
1717 }
1718 break;
1719 }
1720
1721 case 'l': // &l
1722 {
1723 if (*++stre == 't' && *++stre == ';') // <
1724 {
1725 *s++ = '<';
1726 ++stre;
1727
1728 g.push(s, stre - s);
1729 return stre;
1730 }
1731 break;
1732 }
1733
1734 case 'q': // &q
1735 {
1736 if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // "
1737 {
1738 *s++ = '"';
1739 ++stre;
1740
1741 g.push(s, stre - s);
1742 return stre;
1743 }
1744 break;
1745 }
1746
1747 default:
1748 break;
1749 }
1750
1751 return stre;
1752 }
1753
1754 // Utility macro for last character handling
1755 #define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
1756
1757 PUGI__FN char_t* strconv_comment(char_t* s, char_t endch)
1758 {
1759 gap g;
1760
1761 while (true)
1762 {
1763 while (!PUGI__IS_CHARTYPE(*s, ct_parse_comment)) ++s;
1764
1765 if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
1766 {
1767 *s++ = '\n'; // replace first one with 0x0a
1768
1769 if (*s == '\n') g.push(s, 1);
1770 }
1771 else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here
1772 {
1773 *g.flush(s) = 0;
1774
1775 return s + (s[2] == '>' ? 3 : 2);
1776 }
1777 else if (*s == 0)
1778 {
1779 return 0;
1780 }
1781 else ++s;
1782 }
1783 }
1784
1785 PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch)
1786 {
1787 gap g;
1788
1789 while (true)
1790 {
1791 while (!PUGI__IS_CHARTYPE(*s, ct_parse_cdata)) ++s;
1792
1793 if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
1794 {
1795 *s++ = '\n'; // replace first one with 0x0a
1796
1797 if (*s == '\n') g.push(s, 1);
1798 }
1799 else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here
1800 {
1801 *g.flush(s) = 0;
1802
1803 return s + 1;
1804 }
1805 else if (*s == 0)
1806 {
1807 return 0;
1808 }
1809 else ++s;
1810 }
1811 }
1812
1813 typedef char_t* (*strconv_pcdata_t)(char_t*);
1814
1815 template <typename opt_eol, typename opt_escape> struct strconv_pcdata_impl
1816 {
1817 static char_t* parse(char_t* s)
1818 {
1819 gap g;
1820
1821 while (true)
1822 {
1823 while (!PUGI__IS_CHARTYPE(*s, ct_parse_pcdata)) ++s;
1824
1825 if (*s == '<') // PCDATA ends here
1826 {
1827 *g.flush(s) = 0;
1828
1829 return s + 1;
1830 }
1831 else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
1832 {
1833 *s++ = '\n'; // replace first one with 0x0a
1834
1835 if (*s == '\n') g.push(s, 1);
1836 }
1837 else if (opt_escape::value && *s == '&')
1838 {
1839 s = strconv_escape(s, g);
1840 }
1841 else if (*s == 0)
1842 {
1843 return s;
1844 }
1845 else ++s;
1846 }
1847 }
1848 };
1849
1850 PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
1851 {
1852 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20);
1853
1854 switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes)
1855 {
1856 case 0: return strconv_pcdata_impl<opt_false, opt_false>::parse;
1857 case 1: return strconv_pcdata_impl<opt_false, opt_true>::parse;
1858 case 2: return strconv_pcdata_impl<opt_true, opt_false>::parse;
1859 case 3: return strconv_pcdata_impl<opt_true, opt_true>::parse;
1860 default: return 0; // should not get here
1861 }
1862 }
1863
1864 typedef char_t* (*strconv_attribute_t)(char_t*, char_t);
1865
1866 template <typename opt_escape> struct strconv_attribute_impl
1867 {
1868 static char_t* parse_wnorm(char_t* s, char_t end_quote)
1869 {
1870 gap g;
1871
1872 // trim leading whitespaces
1873 if (PUGI__IS_CHARTYPE(*s, ct_space))
1874 {
1875 char_t* str = s;
1876
1877 do ++str;
1878 while (PUGI__IS_CHARTYPE(*str, ct_space));
1879
1880 g.push(s, str - s);
1881 }
1882
1883 while (true)
1884 {
1885 while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) ++s;
1886
1887 if (*s == end_quote)
1888 {
1889 char_t* str = g.flush(s);
1890
1891 do *str-- = 0;
1892 while (PUGI__IS_CHARTYPE(*str, ct_space));
1893
1894 return s + 1;
1895 }
1896 else if (PUGI__IS_CHARTYPE(*s, ct_space))
1897 {
1898 *s++ = ' ';
1899
1900 if (PUGI__IS_CHARTYPE(*s, ct_space))
1901 {
1902 char_t* str = s + 1;
1903 while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
1904
1905 g.push(s, str - s);
1906 }
1907 }
1908 else if (opt_escape::value && *s == '&')
1909 {
1910 s = strconv_escape(s, g);
1911 }
1912 else if (!*s)
1913 {
1914 return 0;
1915 }
1916 else ++s;
1917 }
1918 }
1919
1920 static char_t* parse_wconv(char_t* s, char_t end_quote)
1921 {
1922 gap g;
1923
1924 while (true)
1925 {
1926 while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr_ws)) ++s;
1927
1928 if (*s == end_quote)
1929 {
1930 *g.flush(s) = 0;
1931
1932 return s + 1;
1933 }
1934 else if (PUGI__IS_CHARTYPE(*s, ct_space))
1935 {
1936 if (*s == '\r')
1937 {
1938 *s++ = ' ';
1939
1940 if (*s == '\n') g.push(s, 1);
1941 }
1942 else *s++ = ' ';
1943 }
1944 else if (opt_escape::value && *s == '&')
1945 {
1946 s = strconv_escape(s, g);
1947 }
1948 else if (!*s)
1949 {
1950 return 0;
1951 }
1952 else ++s;
1953 }
1954 }
1955
1956 static char_t* parse_eol(char_t* s, char_t end_quote)
1957 {
1958 gap g;
1959
1960 while (true)
1961 {
1962 while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr)) ++s;
1963
1964 if (*s == end_quote)
1965 {
1966 *g.flush(s) = 0;
1967
1968 return s + 1;
1969 }
1970 else if (*s == '\r')
1971 {
1972 *s++ = '\n';
1973
1974 if (*s == '\n') g.push(s, 1);
1975 }
1976 else if (opt_escape::value && *s == '&')
1977 {
1978 s = strconv_escape(s, g);
1979 }
1980 else if (!*s)
1981 {
1982 return 0;
1983 }
1984 else ++s;
1985 }
1986 }
1987
1988 static char_t* parse_simple(char_t* s, char_t end_quote)
1989 {
1990 gap g;
1991
1992 while (true)
1993 {
1994 while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr)) ++s;
1995
1996 if (*s == end_quote)
1997 {
1998 *g.flush(s) = 0;
1999
2000 return s + 1;
2001 }
2002 else if (opt_escape::value && *s == '&')
2003 {
2004 s = strconv_escape(s, g);
2005 }
2006 else if (!*s)
2007 {
2008 return 0;
2009 }
2010 else ++s;
2011 }
2012 }
2013 };
2014
2015 PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)
2016 {
2017 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);
2018
2019 switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes)
2020 {
2021 case 0: return strconv_attribute_impl<opt_false>::parse_simple;
2022 case 1: return strconv_attribute_impl<opt_true>::parse_simple;
2023 case 2: return strconv_attribute_impl<opt_false>::parse_eol;
2024 case 3: return strconv_attribute_impl<opt_true>::parse_eol;
2025 case 4: return strconv_attribute_impl<opt_false>::parse_wconv;
2026 case 5: return strconv_attribute_impl<opt_true>::parse_wconv;
2027 case 6: return strconv_attribute_impl<opt_false>::parse_wconv;
2028 case 7: return strconv_attribute_impl<opt_true>::parse_wconv;
2029 case 8: return strconv_attribute_impl<opt_false>::parse_wnorm;
2030 case 9: return strconv_attribute_impl<opt_true>::parse_wnorm;
2031 case 10: return strconv_attribute_impl<opt_false>::parse_wnorm;
2032 case 11: return strconv_attribute_impl<opt_true>::parse_wnorm;
2033 case 12: return strconv_attribute_impl<opt_false>::parse_wnorm;
2034 case 13: return strconv_attribute_impl<opt_true>::parse_wnorm;
2035 case 14: return strconv_attribute_impl<opt_false>::parse_wnorm;
2036 case 15: return strconv_attribute_impl<opt_true>::parse_wnorm;
2037 default: return 0; // should not get here
2038 }
2039 }
2040
2041 inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0)
2042 {
2043 xml_parse_result result;
2044 result.status = status;
2045 result.offset = offset;
2046
2047 return result;
2048 }
2049
2050 struct xml_parser
2051 {
2052 xml_allocator alloc;
2053 char_t* error_offset;
2054 xml_parse_status error_status;
2055
2056 // Parser utilities.
2057 #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; }
2058 #define PUGI__OPTSET(OPT) ( optmsk & (OPT) )
2059 #define PUGI__PUSHNODE(TYPE) { cursor = append_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); }
2060 #define PUGI__POPNODE() { cursor = cursor->parent; }
2061 #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; }
2062 #define PUGI__SCANWHILE(X) { while ((X)) ++s; }
2063 #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; }
2064 #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast<char_t*>(0)
2065 #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); }
2066
2067 xml_parser(const xml_allocator& alloc_): alloc(alloc_), error_offset(0), error_status(status_ok)
2068 {
2069 }
2070
2071 // DOCTYPE consists of nested sections of the following possible types:
2072 // <!-- ... -->, <? ... ?>, "...", '...'
2073 // <![...]]>
2074 // <!...>
2075 // First group can not contain nested groups
2076 // Second group can contain nested groups of the same type
2077 // Third group can contain all other groups
2078 char_t* parse_doctype_primitive(char_t* s)
2079 {
2080 if (*s == '"' || *s == '\'')
2081 {
2082 // quoted string
2083 char_t ch = *s++;
2084 PUGI__SCANFOR(*s == ch);
2085 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2086
2087 s++;
2088 }
2089 else if (s[0] == '<' && s[1] == '?')
2090 {
2091 // <? ... ?>
2092 s += 2;
2093 PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
2094 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2095
2096 s += 2;
2097 }
2098 else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-')
2099 {
2100 s += 4;
2101 PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
2102 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2103
2104 s += 4;
2105 }
2106 else PUGI__THROW_ERROR(status_bad_doctype, s);
2107
2108 return s;
2109 }
2110
2111 char_t* parse_doctype_ignore(char_t* s)
2112 {
2113 assert(s[0] == '<' && s[1] == '!' && s[2] == '[');
2114 s++;
2115
2116 while (*s)
2117 {
2118 if (s[0] == '<' && s[1] == '!' && s[2] == '[')
2119 {
2120 // nested ignore section
2121 s = parse_doctype_ignore(s);
2122 if (!s) return s;
2123 }
2124 else if (s[0] == ']' && s[1] == ']' && s[2] == '>')
2125 {
2126 // ignore section end
2127 s += 3;
2128
2129 return s;
2130 }
2131 else s++;
2132 }
2133
2134 PUGI__THROW_ERROR(status_bad_doctype, s);
2135 }
2136
2137 char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel)
2138 {
2139 assert(s[0] == '<' && s[1] == '!');
2140 s++;
2141
2142 while (*s)
2143 {
2144 if (s[0] == '<' && s[1] == '!' && s[2] != '-')
2145 {
2146 if (s[2] == '[')
2147 {
2148 // ignore
2149 s = parse_doctype_ignore(s);
2150 if (!s) return s;
2151 }
2152 else
2153 {
2154 // some control group
2155 s = parse_doctype_group(s, endch, false);
2156 if (!s) return s;
2157 }
2158 }
2159 else if (s[0] == '<' || s[0] == '"' || s[0] == '\'')
2160 {
2161 // unknown tag (forbidden), or some primitive group
2162 s = parse_doctype_primitive(s);
2163 if (!s) return s;
2164 }
2165 else if (*s == '>')
2166 {
2167 s++;
2168
2169 return s;
2170 }
2171 else s++;
2172 }
2173
2174 if (!toplevel || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s);
2175
2176 return s;
2177 }
2178
2179 char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch)
2180 {
2181 // parse node contents, starting with exclamation mark
2182 ++s;
2183
2184 if (*s == '-') // '<!-...'
2185 {
2186 ++s;
2187
2188 if (*s == '-') // '<!--...'
2189 {
2190 ++s;
2191
2192 if (PUGI__OPTSET(parse_comments))
2193 {
2194 PUGI__PUSHNODE(node_comment); // Append a new node on the tree.
2195 cursor->value = s; // Save the offset.
2196 }
2197
2198 if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments))
2199 {
2200 s = strconv_comment(s, endch);
2201
2202 if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value);
2203 }
2204 else
2205 {
2206 // Scan for terminating '-->'.
2207 PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>'));
2208 PUGI__CHECK_ERROR(status_bad_comment, s);
2209
2210 if (PUGI__OPTSET(parse_comments))
2211 *s = 0; // Zero-terminate this segment at the first terminating '-'.
2212
2213 s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'.
2214 }
2215 }
2216 else PUGI__THROW_ERROR(status_bad_comment, s);
2217 }
2218 else if (*s == '[')
2219 {
2220 // '<![CDATA[...'
2221 if (*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[')
2222 {
2223 ++s;
2224
2225 if (PUGI__OPTSET(parse_cdata))
2226 {
2227 PUGI__PUSHNODE(node_cdata); // Append a new node on the tree.
2228 cursor->value = s; // Save the offset.
2229
2230 if (PUGI__OPTSET(parse_eol))
2231 {
2232 s = strconv_cdata(s, endch);
2233
2234 if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
2235 }
2236 else
2237 {
2238 // Scan for terminating ']]>'.
2239 PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
2240 PUGI__CHECK_ERROR(status_bad_cdata, s);
2241
2242 *s++ = 0; // Zero-terminate this segment.
2243 }
2244 }
2245 else // Flagged for discard, but we still have to scan for the terminator.
2246 {
2247 // Scan for terminating ']]>'.
2248 PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
2249 PUGI__CHECK_ERROR(status_bad_cdata, s);
2250
2251 ++s;
2252 }
2253
2254 s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.
2255 }
2256 else PUGI__THROW_ERROR(status_bad_cdata, s);
2257 }
2258 else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E'))
2259 {
2260 s -= 2;
2261
2262 if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s);
2263
2264 char_t* mark = s + 9;
2265
2266 s = parse_doctype_group(s, endch, true);
2267 if (!s) return s;
2268
2269 if (PUGI__OPTSET(parse_doctype))
2270 {
2271 while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
2272
2273 PUGI__PUSHNODE(node_doctype);
2274
2275 cursor->value = mark;
2276
2277 assert((s[0] == 0 && endch == '>') || s[-1] == '>');
2278 s[*s == 0 ? 0 : -1] = 0;
2279
2280 PUGI__POPNODE();
2281 }
2282 }
2283 else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s);
2284 else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s);
2285 else PUGI__THROW_ERROR(status_unrecognized_tag, s);
2286
2287 return s;
2288 }
2289
2290 char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch)
2291 {
2292 // load into registers
2293 xml_node_struct* cursor = ref_cursor;
2294 char_t ch = 0;
2295
2296 // parse node contents, starting with question mark
2297 ++s;
2298
2299 // read PI target
2300 char_t* target = s;
2301
2302 if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s);
2303
2304 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
2305 PUGI__CHECK_ERROR(status_bad_pi, s);
2306
2307 // determine node type; stricmp / strcasecmp is not portable
2308 bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;
2309
2310 if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
2311 {
2312 if (declaration)
2313 {
2314 // disallow non top-level declarations
2315 if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s);
2316
2317 PUGI__PUSHNODE(node_declaration);
2318 }
2319 else
2320 {
2321 PUGI__PUSHNODE(node_pi);
2322 }
2323
2324 cursor->name = target;
2325
2326 PUGI__ENDSEG();
2327
2328 // parse value/attributes
2329 if (ch == '?')
2330 {
2331 // empty node
2332 if (!ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s);
2333 s += (*s == '>');
2334
2335 PUGI__POPNODE();
2336 }
2337 else if (PUGI__IS_CHARTYPE(ch, ct_space))
2338 {
2339 PUGI__SKIPWS();
2340
2341 // scan for tag end
2342 char_t* value = s;
2343
2344 PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>'));
2345 PUGI__CHECK_ERROR(status_bad_pi, s);
2346
2347 if (declaration)
2348 {
2349 // replace ending ? with / so that 'element' terminates properly
2350 *s = '/';
2351
2352 // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES
2353 s = value;
2354 }
2355 else
2356 {
2357 // store value and step over >
2358 cursor->value = value;
2359 PUGI__POPNODE();
2360
2361 PUGI__ENDSEG();
2362
2363 s += (*s == '>');
2364 }
2365 }
2366 else PUGI__THROW_ERROR(status_bad_pi, s);
2367 }
2368 else
2369 {
2370 // scan for tag end
2371 PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>'));
2372 PUGI__CHECK_ERROR(status_bad_pi, s);
2373
2374 s += (s[1] == '>' ? 2 : 1);
2375 }
2376
2377 // store from registers
2378 ref_cursor = cursor;
2379
2380 return s;
2381 }
2382
2383 char_t* parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, char_t endch)
2384 {
2385 strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
2386 strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
2387
2388 char_t ch = 0;
2389 xml_node_struct* cursor = xmldoc;
2390 char_t* mark = s;
2391
2392 while (*s != 0)
2393 {
2394 if (*s == '<')
2395 {
2396 ++s;
2397
2398 LOC_TAG:
2399 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
2400 {
2401 PUGI__PUSHNODE(node_element); // Append a new node to the tree.
2402
2403 cursor->name = s;
2404
2405 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.
2406 PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
2407
2408 if (ch == '>')
2409 {
2410 // end of tag
2411 }
2412 else if (PUGI__IS_CHARTYPE(ch, ct_space))
2413 {
2414 LOC_ATTRIBUTES:
2415 while (true)
2416 {
2417 PUGI__SKIPWS(); // Eat any whitespace.
2418
2419 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
2420 {
2421 xml_attribute_struct* a = append_attribute_ll(cursor, alloc); // Make space for this attribute.
2422 if (!a) PUGI__THROW_ERROR(status_out_of_memory, s);
2423
2424 a->name = s; // Save the offset.
2425
2426 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.
2427 PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
2428
2429 PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
2430 PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
2431
2432 if (PUGI__IS_CHARTYPE(ch, ct_space))
2433 {
2434 PUGI__SKIPWS(); // Eat any whitespace.
2435 PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
2436
2437 ch = *s;
2438 ++s;
2439 }
2440
2441 if (ch == '=') // '<... #=...'
2442 {
2443 PUGI__SKIPWS(); // Eat any whitespace.
2444
2445 if (*s == '"' || *s == '\'') // '<... #="...'
2446 {
2447 ch = *s; // Save quote char to avoid breaking on "''" -or- '""'.
2448 ++s; // Step over the quote.
2449 a->value = s; // Save the offset.
2450
2451 s = strconv_attribute(s, ch);
2452
2453 if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
2454
2455 // After this line the loop continues from the start;
2456 // Whitespaces, / and > are ok, symbols and EOF are wrong,
2457 // everything else will be detected
2458 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s);
2459 }
2460 else PUGI__THROW_ERROR(status_bad_attribute, s);
2461 }
2462 else PUGI__THROW_ERROR(status_bad_attribute, s);
2463 }
2464 else if (*s == '/')
2465 {
2466 ++s;
2467
2468 if (*s == '>')
2469 {
2470 PUGI__POPNODE();
2471 s++;
2472 break;
2473 }
2474 else if (*s == 0 && endch == '>')
2475 {
2476 PUGI__POPNODE();
2477 break;
2478 }
2479 else PUGI__THROW_ERROR(status_bad_start_element, s);
2480 }
2481 else if (*s == '>')
2482 {
2483 ++s;
2484
2485 break;
2486 }
2487 else if (*s == 0 && endch == '>')
2488 {
2489 break;
2490 }
2491 else PUGI__THROW_ERROR(status_bad_start_element, s);
2492 }
2493
2494 // !!!
2495 }
2496 else if (ch == '/') // '<#.../'
2497 {
2498 if (!ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s);
2499
2500 PUGI__POPNODE(); // Pop.
2501
2502 s += (*s == '>');
2503 }
2504 else if (ch == 0)
2505 {
2506 // we stepped over null terminator, backtrack & handle closing tag
2507 --s;
2508
2509 if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s);
2510 }
2511 else PUGI__THROW_ERROR(status_bad_start_element, s);
2512 }
2513 else if (*s == '/')
2514 {
2515 ++s;
2516
2517 char_t* name = cursor->name;
2518 if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s);
2519
2520 while (PUGI__IS_CHARTYPE(*s, ct_symbol))
2521 {
2522 if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s);
2523 }
2524
2525 if (*name)
2526 {
2527 if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s);
2528 else PUGI__THROW_ERROR(status_end_element_mismatch, s);
2529 }
2530
2531 PUGI__POPNODE(); // Pop.
2532
2533 PUGI__SKIPWS();
2534
2535 if (*s == 0)
2536 {
2537 if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
2538 }
2539 else
2540 {
2541 if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
2542 ++s;
2543 }
2544 }
2545 else if (*s == '?') // '<?...'
2546 {
2547 s = parse_question(s, cursor, optmsk, endch);
2548 if (!s) return s;
2549
2550 assert(cursor);
2551 if ((cursor->header & xml_memory_page_type_mask) + 1 == node_declaration) goto LOC_ATTRIBUTES;
2552 }
2553 else if (*s == '!') // '<!...'
2554 {
2555 s = parse_exclamation(s, cursor, optmsk, endch);
2556 if (!s) return s;
2557 }
2558 else if (*s == 0 && endch == '?') PUGI__THROW_ERROR(status_bad_pi, s);
2559 else PUGI__THROW_ERROR(status_unrecognized_tag, s);
2560 }
2561 else
2562 {
2563 mark = s; // Save this offset while searching for a terminator.
2564
2565 PUGI__SKIPWS(); // Eat whitespace if no genuine PCDATA here.
2566
2567 if (*s == '<')
2568 {
2569 // We skipped some whitespace characters because otherwise we would take the tag branch instead of PCDATA one
2570 assert(mark != s);
2571
2572 if (!PUGI__OPTSET(parse_ws_pcdata | parse_ws_pcdata_single))
2573 {
2574 continue;
2575 }
2576 else if (PUGI__OPTSET(parse_ws_pcdata_single))
2577 {
2578 if (s[1] != '/' || cursor->first_child) continue;
2579 }
2580 }
2581
2582 s = mark;
2583
2584 if (cursor->parent)
2585 {
2586 PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree.
2587 cursor->value = s; // Save the offset.
2588
2589 s = strconv_pcdata(s);
2590
2591 PUGI__POPNODE(); // Pop since this is a standalone.
2592
2593 if (!*s) break;
2594 }
2595 else
2596 {
2597 PUGI__SCANFOR(*s == '<'); // '...<'
2598 if (!*s) break;
2599
2600 ++s;
2601 }
2602
2603 // We're after '<'
2604 goto LOC_TAG;
2605 }
2606 }
2607
2608 // check that last tag is closed
2609 if (cursor != xmldoc) PUGI__THROW_ERROR(status_end_element_mismatch, s);
2610
2611 return s;
2612 }
2613
2614 static xml_parse_result parse(char_t* buffer, size_t length, xml_node_struct* root, unsigned int optmsk)
2615 {
2616 xml_document_struct* xmldoc = static_cast<xml_document_struct*>(root);
2617
2618 // store buffer for offset_debug
2619 xmldoc->buffer = buffer;
2620
2621 // early-out for empty documents
2622 if (length == 0) return make_parse_result(status_ok);
2623
2624 // create parser on stack
2625 xml_parser parser(*xmldoc);
2626
2627 // save last character and make buffer zero-terminated (speeds up parsing)
2628 char_t endch = buffer[length - 1];
2629 buffer[length - 1] = 0;
2630
2631 // perform actual parsing
2632 parser.parse(buffer, xmldoc, optmsk, endch);
2633
2634 xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
2635 assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
2636
2637 // update allocator state
2638 *static_cast<xml_allocator*>(xmldoc) = parser.alloc;
2639
2640 // since we removed last character, we have to handle the only possible false positive
2641 if (result && endch == '<')
2642 {
2643 // there's no possible well-formed document with < at the end
2644 return make_parse_result(status_unrecognized_tag, length);
2645 }
2646
2647 return result;
2648 }
2649 };
2650
2651 // Output facilities
2652 PUGI__FN xml_encoding get_write_native_encoding()
2653 {
2654 #ifdef PUGIXML_WCHAR_MODE
2655 return get_wchar_encoding();
2656 #else
2657 return encoding_utf8;
2658 #endif
2659 }
2660
2661 PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
2662 {
2663 // replace wchar encoding with utf implementation
2664 if (encoding == encoding_wchar) return get_wchar_encoding();
2665
2666 // replace utf16 encoding with utf16 with specific endianness
2667 if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2668
2669 // replace utf32 encoding with utf32 with specific endianness
2670 if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2671
2672 // only do autodetection if no explicit encoding is requested
2673 if (encoding != encoding_auto) return encoding;
2674
2675 // assume utf8 encoding
2676 return encoding_utf8;
2677 }
2678
2679#ifdef PUGIXML_WCHAR_MODE
2680 PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
2681 {
2682 assert(length > 0);
2683
2684 // discard last character if it's the lead of a surrogate pair
2685 return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
2686 }
2687
2688 PUGI__FN size_t convert_buffer(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
2689 {
2690 // only endian-swapping is required
2691 if (need_endian_swap_utf(encoding, get_wchar_encoding()))
2692 {
2693 convert_wchar_endian_swap(r_char, data, length);
2694
2695 return length * sizeof(char_t);
2696 }
2697
2698 // convert to utf8
2699 if (encoding == encoding_utf8)
2700 {
2701 uint8_t* dest = r_u8;
2702 uint8_t* end = utf_decoder<utf8_writer>::decode_wchar_block(data, length, dest);
2703
2704 return static_cast<size_t>(end - dest);
2705 }
2706
2707 // convert to utf16
2708 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
2709 {
2710 uint16_t* dest = r_u16;
2711
2712 // convert to native utf16
2713 uint16_t* end = utf_decoder<utf16_writer>::decode_wchar_block(data, length, dest);
2714
2715 // swap if necessary
2716 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2717
2718 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
2719
2720 return static_cast<size_t>(end - dest) * sizeof(uint16_t);
2721 }
2722
2723 // convert to utf32
2724 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
2725 {
2726 uint32_t* dest = r_u32;
2727
2728 // convert to native utf32
2729 uint32_t* end = utf_decoder<utf32_writer>::decode_wchar_block(data, length, dest);
2730
2731 // swap if necessary
2732 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2733
2734 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
2735
2736 return static_cast<size_t>(end - dest) * sizeof(uint32_t);
2737 }
2738
2739 // convert to latin1
2740 if (encoding == encoding_latin1)
2741 {
2742 uint8_t* dest = r_u8;
2743 uint8_t* end = utf_decoder<latin1_writer>::decode_wchar_block(data, length, dest);
2744
2745 return static_cast<size_t>(end - dest);
2746 }
2747
2748 assert(!"Invalid encoding");
2749 return 0;
2750 }
2751#else
2752 PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
2753 {
2754 assert(length > 4);
2755
2756 for (size_t i = 1; i <= 4; ++i)
2757 {
2758 uint8_t ch = static_cast<uint8_t>(data[length - i]);
2759
2760 // either a standalone character or a leading one
2761 if ((ch & 0xc0) != 0x80) return length - i;
2762 }
2763
2764 // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk
2765 return length;
2766 }
2767
2768 PUGI__FN size_t convert_buffer(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
2769 {
2770 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
2771 {
2772 uint16_t* dest = r_u16;
2773
2774 // convert to native utf16
2775 uint16_t* end = utf_decoder<utf16_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
2776
2777 // swap if necessary
2778 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2779
2780 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
2781
2782 return static_cast<size_t>(end - dest) * sizeof(uint16_t);
2783 }
2784
2785 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
2786 {
2787 uint32_t* dest = r_u32;
2788
2789 // convert to native utf32
2790 uint32_t* end = utf_decoder<utf32_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
2791
2792 // swap if necessary
2793 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2794
2795 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
2796
2797 return static_cast<size_t>(end - dest) * sizeof(uint32_t);
2798 }
2799
2800 if (encoding == encoding_latin1)
2801 {
2802 uint8_t* dest = r_u8;
2803 uint8_t* end = utf_decoder<latin1_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
2804
2805 return static_cast<size_t>(end - dest);
2806 }
2807
2808 assert(!"Invalid encoding");
2809 return 0;
2810 }
2811#endif
2812
2813 class xml_buffered_writer
2814 {
2815 xml_buffered_writer(const xml_buffered_writer&);
2816 xml_buffered_writer& operator=(const xml_buffered_writer&);
2817
2818 public:
2819 xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
2820 {
2821 PUGI__STATIC_ASSERT(bufcapacity >= 8);
2822 }
2823
2824 ~xml_buffered_writer()
2825 {
2826 flush();
2827 }
2828
2829 void flush()
2830 {
2831 flush(buffer, bufsize);
2832 bufsize = 0;
2833 }
2834
2835 void flush(const char_t* data, size_t size)
2836 {
2837 if (size == 0) return;
2838
2839 // fast path, just write data
2840 if (encoding == get_write_native_encoding())
2841 writer.write(data, size * sizeof(char_t));
2842 else
2843 {
2844 // convert chunk
2845 size_t result = convert_buffer(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding);
2846 assert(result <= sizeof(scratch));
2847
2848 // write data
2849 writer.write(scratch.data_u8, result);
2850 }
2851 }
2852
2853 void write(const char_t* data, size_t length)
2854 {
2855 if (bufsize + length > bufcapacity)
2856 {
2857 // flush the remaining buffer contents
2858 flush();
2859
2860 // handle large chunks
2861 if (length > bufcapacity)
2862 {
2863 if (encoding == get_write_native_encoding())
2864 {
2865 // fast path, can just write data chunk
2866 writer.write(data, length * sizeof(char_t));
2867 return;
2868 }
2869
2870 // need to convert in suitable chunks
2871 while (length > bufcapacity)
2872 {
2873 // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer
2874 // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)
2875 size_t chunk_size = get_valid_length(data, bufcapacity);
2876
2877 // convert chunk and write
2878 flush(data, chunk_size);
2879
2880 // iterate
2881 data += chunk_size;
2882 length -= chunk_size;
2883 }
2884
2885 // small tail is copied below
2886 bufsize = 0;
2887 }
2888 }
2889
2890 memcpy(buffer + bufsize, data, length * sizeof(char_t));
2891 bufsize += length;
2892 }
2893
2894 void write(const char_t* data)
2895 {
2896 write(data, strlength(data));
2897 }
2898
2899 void write(char_t d0)
2900 {
2901 if (bufsize + 1 > bufcapacity) flush();
2902
2903 buffer[bufsize + 0] = d0;
2904 bufsize += 1;
2905 }
2906
2907 void write(char_t d0, char_t d1)
2908 {
2909 if (bufsize + 2 > bufcapacity) flush();
2910
2911 buffer[bufsize + 0] = d0;
2912 buffer[bufsize + 1] = d1;
2913 bufsize += 2;
2914 }
2915
2916 void write(char_t d0, char_t d1, char_t d2)
2917 {
2918 if (bufsize + 3 > bufcapacity) flush();
2919
2920 buffer[bufsize + 0] = d0;
2921 buffer[bufsize + 1] = d1;
2922 buffer[bufsize + 2] = d2;
2923 bufsize += 3;
2924 }
2925
2926 void write(char_t d0, char_t d1, char_t d2, char_t d3)
2927 {
2928 if (bufsize + 4 > bufcapacity) flush();
2929
2930 buffer[bufsize + 0] = d0;
2931 buffer[bufsize + 1] = d1;
2932 buffer[bufsize + 2] = d2;
2933 buffer[bufsize + 3] = d3;
2934 bufsize += 4;
2935 }
2936
2937 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
2938 {
2939 if (bufsize + 5 > bufcapacity) flush();
2940
2941 buffer[bufsize + 0] = d0;
2942 buffer[bufsize + 1] = d1;
2943 buffer[bufsize + 2] = d2;
2944 buffer[bufsize + 3] = d3;
2945 buffer[bufsize + 4] = d4;
2946 bufsize += 5;
2947 }
2948
2949 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
2950 {
2951 if (bufsize + 6 > bufcapacity) flush();
2952
2953 buffer[bufsize + 0] = d0;
2954 buffer[bufsize + 1] = d1;
2955 buffer[bufsize + 2] = d2;
2956 buffer[bufsize + 3] = d3;
2957 buffer[bufsize + 4] = d4;
2958 buffer[bufsize + 5] = d5;
2959 bufsize += 6;
2960 }
2961
2962 // utf8 maximum expansion: x4 (-> utf32)
2963 // utf16 maximum expansion: x2 (-> utf32)
2964 // utf32 maximum expansion: x1
2965 enum
2966 {
2967 bufcapacitybytes =
2968 #ifdef PUGIXML_MEMORY_OUTPUT_STACK
2969 PUGIXML_MEMORY_OUTPUT_STACK
2970 #else
2971 10240
2972 #endif
2973 ,
2974 bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4)
2975 };
2976
2977 char_t buffer[bufcapacity];
2978
2979 union
2980 {
2981 uint8_t data_u8[4 * bufcapacity];
2982 uint16_t data_u16[2 * bufcapacity];
2983 uint32_t data_u32[bufcapacity];
2984 char_t data_char[bufcapacity];
2985 } scratch;
2986
2987 xml_writer& writer;
2988 size_t bufsize;
2989 xml_encoding encoding;
2990 };
2991
2992 PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type)
2993 {
2994 while (*s)
2995 {
2996 const char_t* prev = s;
2997
2998 // While *s is a usual symbol
2999 while (!PUGI__IS_CHARTYPEX(*s, type)) ++s;
3000
3001 writer.write(prev, static_cast<size_t>(s - prev));
3002
3003 switch (*s)
3004 {
3005 case 0: break;
3006 case '&':
3007 writer.write('&', 'a', 'm', 'p', ';');
3008 ++s;
3009 break;
3010 case '<':
3011 writer.write('&', 'l', 't', ';');
3012 ++s;
3013 break;
3014 case '>':
3015 writer.write('&', 'g', 't', ';');
3016 ++s;
3017 break;
3018 case '"':
3019 writer.write('&', 'q', 'u', 'o', 't', ';');
3020 ++s;
3021 break;
3022 default: // s is not a usual symbol
3023 {
3024 unsigned int ch = static_cast<unsigned int>(*s++);
3025 assert(ch < 32);
3026
3027 writer.write('&', '#', static_cast<char_t>((ch / 10) + '0'), static_cast<char_t>((ch % 10) + '0'), ';');
3028 }
3029 }
3030 }
3031 }
3032
3033 PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
3034 {
3035 if (flags & format_no_escapes)
3036 writer.write(s);
3037 else
3038 text_output_escaped(writer, s, type);
3039 }
3040
3041 PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s)
3042 {
3043 do
3044 {
3045 writer.write('<', '!', '[', 'C', 'D');
3046 writer.write('A', 'T', 'A', '[');
3047
3048 const char_t* prev = s;
3049
3050 // look for ]]> sequence - we can't output it as is since it terminates CDATA
3051 while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s;
3052
3053 // skip ]] if we stopped at ]]>, > will go to the next CDATA section
3054 if (*s) s += 2;
3055
3056 writer.write(prev, static_cast<size_t>(s - prev));
3057
3058 writer.write(']', ']', '>');
3059 }
3060 while (*s);
3061 }
3062
3063 PUGI__FN void node_output_attributes(xml_buffered_writer& writer, const xml_node& node, unsigned int flags)
3064 {
3065 const char_t* default_name = PUGIXML_TEXT(":anonymous");
3066
3067 for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute())
3068 {
3069 writer.write(' ');
3070 writer.write(a.name()[0] ? a.name() : default_name);
3071 writer.write('=', '"');
3072
3073 text_output(writer, a.value(), ctx_special_attr, flags);
3074
3075 writer.write('"');
3076 }
3077 }
3078
3079 PUGI__FN void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth)
3080 {
3081 const char_t* default_name = PUGIXML_TEXT(":anonymous");
3082
3083 if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
3084 for (unsigned int i = 0; i < depth; ++i) writer.write(indent);
3085
3086 switch (node.type())
3087 {
3088 case node_document:
3089 {
3090 for (xml_node n = node.first_child(); n; n = n.next_sibling())
3091 node_output(writer, n, indent, flags, depth);
3092 break;
3093 }
3094
3095 case node_element:
3096 {
3097 const char_t* name = node.name()[0] ? node.name() : default_name;
3098
3099 writer.write('<');
3100 writer.write(name);
3101
3102 node_output_attributes(writer, node, flags);
3103
3104 if (flags & format_raw)
3105 {
3106 if (!node.first_child())
3107 writer.write(' ', '/', '>');
3108 else
3109 {
3110 writer.write('>');
3111
3112 for (xml_node n = node.first_child(); n; n = n.next_sibling())
3113 node_output(writer, n, indent, flags, depth + 1);
3114
3115 writer.write('<', '/');
3116 writer.write(name);
3117 writer.write('>');
3118 }
3119 }
3120 else if (!node.first_child())
3121 writer.write(' ', '/', '>', '\n');
3122 else if (node.first_child() == node.last_child() && (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata))
3123 {
3124 writer.write('>');
3125
3126 if (node.first_child().type() == node_pcdata)
3127 text_output(writer, node.first_child().value(), ctx_special_pcdata, flags);
3128 else
3129 text_output_cdata(writer, node.first_child().value());
3130
3131 writer.write('<', '/');
3132 writer.write(name);
3133 writer.write('>', '\n');
3134 }
3135 else
3136 {
3137 writer.write('>', '\n');
3138
3139 for (xml_node n = node.first_child(); n; n = n.next_sibling())
3140 node_output(writer, n, indent, flags, depth + 1);
3141
3142 if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
3143 for (unsigned int i = 0; i < depth; ++i) writer.write(indent);
3144
3145 writer.write('<', '/');
3146 writer.write(name);
3147 writer.write('>', '\n');
3148 }
3149
3150 break;
3151 }
3152
3153 case node_pcdata:
3154 text_output(writer, node.value(), ctx_special_pcdata, flags);
3155 if ((flags & format_raw) == 0) writer.write('\n');
3156 break;
3157
3158 case node_cdata:
3159 text_output_cdata(writer, node.value());
3160 if ((flags & format_raw) == 0) writer.write('\n');
3161 break;
3162
3163 case node_comment:
3164 writer.write('<', '!', '-', '-');
3165 writer.write(node.value());
3166 writer.write('-', '-', '>');
3167 if ((flags & format_raw) == 0) writer.write('\n');
3168 break;
3169
3170 case node_pi:
3171 case node_declaration:
3172 writer.write('<', '?');
3173 writer.write(node.name()[0] ? node.name() : default_name);
3174
3175 if (node.type() == node_declaration)
3176 {
3177 node_output_attributes(writer, node, flags);
3178 }
3179 else if (node.value()[0])
3180 {
3181 writer.write(' ');
3182 writer.write(node.value());
3183 }
3184
3185 writer.write('?', '>');
3186 if ((flags & format_raw) == 0) writer.write('\n');
3187 break;
3188
3189 case node_doctype:
3190 writer.write('<', '!', 'D', 'O', 'C');
3191 writer.write('T', 'Y', 'P', 'E');
3192
3193 if (node.value()[0])
3194 {
3195 writer.write(' ');
3196 writer.write(node.value());
3197 }
3198
3199 writer.write('>');
3200 if ((flags & format_raw) == 0) writer.write('\n');
3201 break;
3202
3203 default:
3204 assert(!"Invalid node type");
3205 }
3206 }
3207
3208 inline bool has_declaration(const xml_node& node)
3209 {
3210 for (xml_node child = node.first_child(); child; child = child.next_sibling())
3211 {
3212 xml_node_type type = child.type();
3213
3214 if (type == node_declaration) return true;
3215 if (type == node_element) return false;
3216 }
3217
3218 return false;
3219 }
3220
3221 inline bool allow_insert_child(xml_node_type parent, xml_node_type child)
3222 {
3223 if (parent != node_document && parent != node_element) return false;
3224 if (child == node_document || child == node_null) return false;
3225 if (parent != node_document && (child == node_declaration || child == node_doctype)) return false;
3226
3227 return true;
3228 }
3229
3230 PUGI__FN void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip)
3231 {
3232 assert(dest.type() == source.type());
3233
3234 switch (source.type())
3235 {
3236 case node_element:
3237 {
3238 dest.set_name(source.name());
3239
3240 for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
3241 dest.append_attribute(a.name()).set_value(a.value());
3242
3243 for (xml_node c = source.first_child(); c; c = c.next_sibling())
3244 {
3245 if (c == skip) continue;
3246
3247 xml_node cc = dest.append_child(c.type());
3248 assert(cc);
3249
3250 recursive_copy_skip(cc, c, skip);
3251 }
3252
3253 break;
3254 }
3255
3256 case node_pcdata:
3257 case node_cdata:
3258 case node_comment:
3259 case node_doctype:
3260 dest.set_value(source.value());
3261 break;
3262
3263 case node_pi:
3264 dest.set_name(source.name());
3265 dest.set_value(source.value());
3266 break;
3267
3268 case node_declaration:
3269 {
3270 dest.set_name(source.name());
3271
3272 for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
3273 dest.append_attribute(a.name()).set_value(a.value());
3274
3275 break;
3276 }
3277
3278 default:
3279 assert(!"Invalid node type");
3280 }
3281 }
3282
3283 inline bool is_text_node(xml_node_struct* node)
3284 {
3285 xml_node_type type = static_cast<xml_node_type>((node->header & impl::xml_memory_page_type_mask) + 1);
3286
3287 return type == node_pcdata || type == node_cdata;
3288 }
3289
3290 // get value with conversion functions
3291 PUGI__FN unsigned short get_value_ushort(const char_t* value, unsigned short def)
3292 {
3293 if (!value) return def;
3294
3295 #ifdef PUGIXML_WCHAR_MODE
3296 return static_cast<unsigned short>(wcstoul(value, 0, 10));
3297 #else
3298 return static_cast<unsigned short>(strtoul(value, 0, 10));
3299 #endif
3300 }
3301
3302 PUGI__FN int get_value_int(const char_t* value, int def)
3303 {
3304 if (!value) return def;
3305
3306 #ifdef PUGIXML_WCHAR_MODE
3307 return static_cast<int>(wcstol(value, 0, 10));
3308 #else
3309 return static_cast<int>(strtol(value, 0, 10));
3310 #endif
3311 }
3312
3313 PUGI__FN unsigned int get_value_uint(const char_t* value, unsigned int def)
3314 {
3315 if (!value) return def;
3316
3317 #ifdef PUGIXML_WCHAR_MODE
3318 return static_cast<unsigned int>(wcstoul(value, 0, 10));
3319 #else
3320 return static_cast<unsigned int>(strtoul(value, 0, 10));
3321 #endif
3322 }
3323
3324 PUGI__FN double get_value_double(const char_t* value, double def)
3325 {
3326 if (!value) return def;
3327
3328 #ifdef PUGIXML_WCHAR_MODE
3329 return wcstod(value, 0);
3330 #else
3331 return strtod(value, 0);
3332 #endif
3333 }
3334
3335 PUGI__FN float get_value_float(const char_t* value, float def)
3336 {
3337 if (!value) return def;
3338
3339 #ifdef PUGIXML_WCHAR_MODE
3340 return static_cast<float>(wcstod(value, 0));
3341 #else
3342 return static_cast<float>(strtod(value, 0));
3343 #endif
3344 }
3345
3346 PUGI__FN bool get_value_bool(const char_t* value, bool def)
3347 {
3348 if (!value) return def;
3349
3350 // only look at first char
3351 char_t first = *value;
3352
3353 // 1*, t* (true), T* (True), y* (yes), Y* (YES)
3354 return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
3355 }
3356
3357 // set value with conversion functions
3358 PUGI__FN bool set_value_buffer(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char (&buf)[128])
3359 {
3360 #ifdef PUGIXML_WCHAR_MODE
3361 char_t wbuf[128];
3362 impl::widen_ascii(wbuf, buf);
3363
3364 return strcpy_insitu(dest, header, header_mask, wbuf);
3365 #else
3366 return strcpy_insitu(dest, header, header_mask, buf);
3367 #endif
3368 }
3369
3370 PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, int value)
3371 {
3372 char buf[128];
3373 sprintf(buf, "%d", value);
3374
3375 return set_value_buffer(dest, header, header_mask, buf);
3376 }
3377
3378 PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, unsigned int value)
3379 {
3380 char buf[128];
3381 sprintf(buf, "%u", value);
3382
3383 return set_value_buffer(dest, header, header_mask, buf);
3384 }
3385
3386 PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, double value)
3387 {
3388 char buf[128];
3389 sprintf(buf, "%g", value);
3390
3391 return set_value_buffer(dest, header, header_mask, buf);
3392 }
3393
3394 PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, bool value)
3395 {
3396 return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
3397 }
3398
3399 // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick
3400 PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result)
3401 {
3402 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
3403 // there are 64-bit versions of fseek/ftell, let's use them
3404 typedef __int64 length_type;
3405
3406 _fseeki64(file, 0, SEEK_END);
3407 length_type length = _ftelli64(file);
3408 _fseeki64(file, 0, SEEK_SET);
3409 #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__)
3410 // there are 64-bit versions of fseek/ftell, let's use them
3411 typedef off64_t length_type;
3412
3413 fseeko64(file, 0, SEEK_END);
3414 length_type length = ftello64(file);
3415 fseeko64(file, 0, SEEK_SET);
3416 #else
3417 // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway.
3418 typedef long length_type;
3419
3420 fseek(file, 0, SEEK_END);
3421 length_type length = ftell(file);
3422 fseek(file, 0, SEEK_SET);
3423 #endif
3424
3425 // check for I/O errors
3426 if (length < 0) return status_io_error;
3427
3428 // check for overflow
3429 size_t result = static_cast<size_t>(length);
3430
3431 if (static_cast<length_type>(result) != length) return status_out_of_memory;
3432
3433 // finalize
3434 out_result = result;
3435
3436 return status_ok;
3437 }
3438
3439 PUGI__FN xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding)
3440 {
3441 if (!file) return make_parse_result(status_file_not_found);
3442
3443 // get file size (can result in I/O errors)
3444 size_t size = 0;
3445 xml_parse_status size_status = get_file_size(file, size);
3446
3447 if (size_status != status_ok)
3448 {
3449 fclose(file);
3450 return make_parse_result(size_status);
3451 }
3452
3453 // allocate buffer for the whole file
3454 char* contents = static_cast<char*>(xml_memory::allocate(size > 0 ? size : 1));
3455
3456 if (!contents)
3457 {
3458 fclose(file);
3459 return make_parse_result(status_out_of_memory);
3460 }
3461
3462 // read file in memory
3463 size_t read_size = fread(contents, 1, size, file);
3464 fclose(file);
3465
3466 if (read_size != size)
3467 {
3468 xml_memory::deallocate(contents);
3469 return make_parse_result(status_io_error);
3470 }
3471
3472 return doc.load_buffer_inplace_own(contents, size, options, encoding);
3473 }
3474
3475#ifndef PUGIXML_NO_STL
3476 template <typename T> struct xml_stream_chunk
3477 {
3478 static xml_stream_chunk* create()
3479 {
3480 void* memory = xml_memory::allocate(sizeof(xml_stream_chunk));
3481
3482 return new (memory) xml_stream_chunk();
3483 }
3484
3485 static void destroy(void* ptr)
3486 {
3487 xml_stream_chunk* chunk = static_cast<xml_stream_chunk*>(ptr);
3488
3489 // free chunk chain
3490 while (chunk)
3491 {
3492 xml_stream_chunk* next = chunk->next;
3493 xml_memory::deallocate(chunk);
3494 chunk = next;
3495 }
3496 }
3497
3498 xml_stream_chunk(): next(0), size(0)
3499 {
3500 }
3501
3502 xml_stream_chunk* next;
3503 size_t size;
3504
3505 T data[xml_memory_page_size / sizeof(T)];
3506 };
3507
3508 template <typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
3509 {
3510 buffer_holder chunks(0, xml_stream_chunk<T>::destroy);
3511
3512 // read file to a chunk list
3513 size_t total = 0;
3514 xml_stream_chunk<T>* last = 0;
3515
3516 while (!stream.eof())
3517 {
3518 // allocate new chunk
3519 xml_stream_chunk<T>* chunk = xml_stream_chunk<T>::create();
3520 if (!chunk) return status_out_of_memory;
3521
3522 // append chunk to list
3523 if (last) last = last->next = chunk;
3524 else chunks.data = last = chunk;
3525
3526 // read data to chunk
3527 stream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T)));
3528 chunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T);
3529
3530 // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors
3531 if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
3532
3533 // guard against huge files (chunk size is small enough to make this overflow check work)
3534 if (total + chunk->size < total) return status_out_of_memory;
3535 total += chunk->size;
3536 }
3537
3538 // copy chunk list to a contiguous buffer
3539 char* buffer = static_cast<char*>(xml_memory::allocate(total));
3540 if (!buffer) return status_out_of_memory;
3541
3542 char* write = buffer;
3543
3544 for (xml_stream_chunk<T>* chunk = static_cast<xml_stream_chunk<T>*>(chunks.data); chunk; chunk = chunk->next)
3545 {
3546 assert(write + chunk->size <= buffer + total);
3547 memcpy(write, chunk->data, chunk->size);
3548 write += chunk->size;
3549 }
3550
3551 assert(write == buffer + total);
3552
3553 // return buffer
3554 *out_buffer = buffer;
3555 *out_size = total;
3556
3557 return status_ok;
3558 }
3559
3560 template <typename T> PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
3561 {
3562 // get length of remaining data in stream
3563 typename std::basic_istream<T>::pos_type pos = stream.tellg();
3564 stream.seekg(0, std::ios::end);
3565 std::streamoff length = stream.tellg() - pos;
3566 stream.seekg(pos);
3567
3568 if (stream.fail() || pos < 0) return status_io_error;
3569
3570 // guard against huge files
3571 size_t read_length = static_cast<size_t>(length);
3572
3573 if (static_cast<std::streamsize>(read_length) != length || length < 0) return status_out_of_memory;
3574
3575 // read stream data into memory (guard against stream exceptions with buffer holder)
3576 buffer_holder buffer(xml_memory::allocate((read_length > 0 ? read_length : 1) * sizeof(T)), xml_memory::deallocate);
3577 if (!buffer.data) return status_out_of_memory;
3578
3579 stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length));
3580
3581 // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors
3582 if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
3583
3584 // return buffer
3585 size_t actual_length = static_cast<size_t>(stream.gcount());
3586 assert(actual_length <= read_length);
3587
3588 *out_buffer = buffer.release();
3589 *out_size = actual_length * sizeof(T);
3590
3591 return status_ok;
3592 }
3593
3594 template <typename T> PUGI__FN xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding)
3595 {
3596 void* buffer = 0;
3597 size_t size = 0;
3598
3599 // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory)
3600 xml_parse_status status = (stream.tellg() < 0) ? load_stream_data_noseek(stream, &buffer, &size) : load_stream_data_seek(stream, &buffer, &size);
3601 if (status != status_ok) return make_parse_result(status);
3602
3603 return doc.load_buffer_inplace_own(buffer, size, options, encoding);
3604 }
3605#endif
3606
3607#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && !defined(__STRICT_ANSI__))
3608 PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
3609 {
3610 return _wfopen(path, mode);
3611 }
3612#else
3613 PUGI__FN char* convert_path_heap(const wchar_t* str)
3614 {
3615 assert(str);
3616
3617 // first pass: get length in utf8 characters
3618 size_t length = wcslen(str);
3619 size_t size = as_utf8_begin(str, length);
3620
3621 // allocate resulting string
3622 char* result = static_cast<char*>(xml_memory::allocate(size + 1));
3623 if (!result) return 0;
3624
3625 // second pass: convert to utf8
3626 as_utf8_end(result, size, str, length);
3627
3628 return result;
3629 }
3630
3631 PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
3632 {
3633 // there is no standard function to open wide paths, so our best bet is to try utf8 path
3634 char* path_utf8 = convert_path_heap(path);
3635 if (!path_utf8) return 0;
3636
3637 // convert mode to ASCII (we mirror _wfopen interface)
3638 char mode_ascii[4] = {0};
3639 for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]);
3640
3641 // try to open the utf8 path
3642 FILE* result = fopen(path_utf8, mode_ascii);
3643
3644 // free dummy buffer
3645 xml_memory::deallocate(path_utf8);
3646
3647 return result;
3648 }
3649#endif
3650
3651 PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding)
3652 {
3653 if (!file) return false;
3654
3655 xml_writer_file writer(file);
3656 doc.save(writer, indent, flags, encoding);
3657
3658 int result = ferror(file);
3659
3660 fclose(file);
3661
3662 return result == 0;
3663 }
3664PUGI__NS_END
3665
3666namespace pugi
3667{
3668 PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_)
3669 {
3670 }
3671
3672 PUGI__FN void xml_writer_file::write(const void* data, size_t size)
3673 {
3674 size_t result = fwrite(data, 1, size, static_cast<FILE*>(file));
3675 (void)!result; // unfortunately we can't do proper error handling here
3676 }
3677
3678#ifndef PUGIXML_NO_STL
3679 PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
3680 {
3681 }
3682
3683 PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
3684 {
3685 }
3686
3687 PUGI__FN void xml_writer_stream::write(const void* data, size_t size)
3688 {
3689 if (narrow_stream)
3690 {
3691 assert(!wide_stream);
3692 narrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
3693 }
3694 else
3695 {
3696 assert(wide_stream);
3697 assert(size % sizeof(wchar_t) == 0);
3698
3699 wide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size / sizeof(wchar_t)));
3700 }
3701 }
3702#endif
3703
3704 PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0)
3705 {
3706 }
3707
3708 PUGI__FN xml_tree_walker::~xml_tree_walker()
3709 {
3710 }
3711
3712 PUGI__FN int xml_tree_walker::depth() const
3713 {
3714 return _depth;
3715 }
3716
3717 PUGI__FN bool xml_tree_walker::begin(xml_node&)
3718 {
3719 return true;
3720 }
3721
3722 PUGI__FN bool xml_tree_walker::end(xml_node&)
3723 {
3724 return true;
3725 }
3726
3727 PUGI__FN xml_attribute::xml_attribute(): _attr(0)
3728 {
3729 }
3730
3731 PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)
3732 {
3733 }
3734
3735 PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***)
3736 {
3737 }
3738
3739 PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const
3740 {
3741 return _attr ? unspecified_bool_xml_attribute : 0;
3742 }
3743
3744 PUGI__FN bool xml_attribute::operator!() const
3745 {
3746 return !_attr;
3747 }
3748
3749 PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const
3750 {
3751 return (_attr == r._attr);
3752 }
3753
3754 PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const
3755 {
3756 return (_attr != r._attr);
3757 }
3758
3759 PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const
3760 {
3761 return (_attr < r._attr);
3762 }
3763
3764 PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const
3765 {
3766 return (_attr > r._attr);
3767 }
3768
3769 PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const
3770 {
3771 return (_attr <= r._attr);
3772 }
3773
3774 PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const
3775 {
3776 return (_attr >= r._attr);
3777 }
3778
3779 PUGI__FN xml_attribute xml_attribute::next_attribute() const
3780 {
3781 return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute();
3782 }
3783
3784 PUGI__FN xml_attribute xml_attribute::previous_attribute() const
3785 {
3786 return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute();
3787 }
3788
3789 PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const
3790 {
3791 return (_attr && _attr->value) ? _attr->value : def;
3792 }
3793
3794 PUGI__FN unsigned short xml_attribute::as_ushort(unsigned short def) const
3795 {
3796 return impl::get_value_ushort(_attr ? _attr->value : 0, def);
3797 }
3798
3799 PUGI__FN int xml_attribute::as_int(int def) const
3800 {
3801 return impl::get_value_int(_attr ? _attr->value : 0, def);
3802 }
3803
3804 PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
3805 {
3806 return impl::get_value_uint(_attr ? _attr->value : 0, def);
3807 }
3808
3809 PUGI__FN double xml_attribute::as_double(double def) const
3810 {
3811 return impl::get_value_double(_attr ? _attr->value : 0, def);
3812 }
3813
3814 PUGI__FN float xml_attribute::as_float(float def) const
3815 {
3816 return impl::get_value_float(_attr ? _attr->value : 0, def);
3817 }
3818
3819 PUGI__FN bool xml_attribute::as_bool(bool def) const
3820 {
3821 return impl::get_value_bool(_attr ? _attr->value : 0, def);
3822 }
3823
3824 PUGI__FN bool xml_attribute::empty() const
3825 {
3826 return !_attr;
3827 }
3828
3829 PUGI__FN const char_t* xml_attribute::name() const
3830 {
3831 return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT("");
3832 }
3833
3834 PUGI__FN const char_t* xml_attribute::value() const
3835 {
3836 return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT("");
3837 }
3838
3839 PUGI__FN size_t xml_attribute::hash_value() const
3840 {
3841 return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
3842 }
3843
3844 PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const
3845 {
3846 return _attr;
3847 }
3848
3849 PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs)
3850 {
3851 set_value(rhs);
3852 return *this;
3853 }
3854
3855 PUGI__FN xml_attribute& xml_attribute::operator=(int rhs)
3856 {
3857 set_value(rhs);
3858 return *this;
3859 }
3860
3861 PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs)
3862 {
3863 set_value(rhs);
3864 return *this;
3865 }
3866
3867 PUGI__FN xml_attribute& xml_attribute::operator=(double rhs)
3868 {
3869 set_value(rhs);
3870 return *this;
3871 }
3872
3873 PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs)
3874 {
3875 set_value(rhs);
3876 return *this;
3877 }
3878
3879 PUGI__FN bool xml_attribute::set_name(const char_t* rhs)
3880 {
3881 if (!_attr) return false;
3882
3883 return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs);
3884 }
3885
3886 PUGI__FN bool xml_attribute::set_value(const char_t* rhs)
3887 {
3888 if (!_attr) return false;
3889
3890 return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
3891 }
3892
3893 PUGI__FN bool xml_attribute::set_value(int rhs)
3894 {
3895 if (!_attr) return false;
3896
3897 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
3898 }
3899
3900 PUGI__FN bool xml_attribute::set_value(unsigned int rhs)
3901 {
3902 if (!_attr) return false;
3903
3904 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
3905 }
3906
3907 PUGI__FN bool xml_attribute::set_value(double rhs)
3908 {
3909 if (!_attr) return false;
3910
3911 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
3912 }
3913
3914 PUGI__FN bool xml_attribute::set_value(bool rhs)
3915 {
3916 if (!_attr) return false;
3917
3918 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
3919 }
3920
3921#ifdef __BORLANDC__
3922 PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs)
3923 {
3924 return (bool)lhs && rhs;
3925 }
3926
3927 PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs)
3928 {
3929 return (bool)lhs || rhs;
3930 }
3931#endif
3932
3933 PUGI__FN xml_node::xml_node(): _root(0)
3934 {
3935 }
3936
3937 PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p)
3938 {
3939 }
3940
3941 PUGI__FN static void unspecified_bool_xml_node(xml_node***)
3942 {
3943 }
3944
3945 PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const
3946 {
3947 return _root ? unspecified_bool_xml_node : 0;
3948 }
3949
3950 PUGI__FN bool xml_node::operator!() const
3951 {
3952 return !_root;
3953 }
3954
3955 PUGI__FN xml_node::iterator xml_node::begin() const
3956 {
3957 return iterator(_root ? _root->first_child : 0, _root);
3958 }
3959
3960 PUGI__FN xml_node::iterator xml_node::end() const
3961 {
3962 return iterator(0, _root);
3963 }
3964
3965 PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const
3966 {
3967 return attribute_iterator(_root ? _root->first_attribute : 0, _root);
3968 }
3969
3970 PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const
3971 {
3972 return attribute_iterator(0, _root);
3973 }
3974
3975 PUGI__FN xml_object_range<xml_node_iterator> xml_node::children() const
3976 {
3977 return xml_object_range<xml_node_iterator>(begin(), end());
3978 }
3979
3980 PUGI__FN xml_object_range<xml_named_node_iterator> xml_node::children(const char_t* name_) const
3981 {
3982 return xml_object_range<xml_named_node_iterator>(xml_named_node_iterator(child(name_), name_), xml_named_node_iterator());
3983 }
3984
3985 PUGI__FN xml_object_range<xml_attribute_iterator> xml_node::attributes() const
3986 {
3987 return xml_object_range<xml_attribute_iterator>(attributes_begin(), attributes_end());
3988 }
3989
3990 PUGI__FN bool xml_node::operator==(const xml_node& r) const
3991 {
3992 return (_root == r._root);
3993 }
3994
3995 PUGI__FN bool xml_node::operator!=(const xml_node& r) const
3996 {
3997 return (_root != r._root);
3998 }
3999
4000 PUGI__FN bool xml_node::operator<(const xml_node& r) const
4001 {
4002 return (_root < r._root);
4003 }
4004
4005 PUGI__FN bool xml_node::operator>(const xml_node& r) const
4006 {
4007 return (_root > r._root);
4008 }
4009
4010 PUGI__FN bool xml_node::operator<=(const xml_node& r) const
4011 {
4012 return (_root <= r._root);
4013 }
4014
4015 PUGI__FN bool xml_node::operator>=(const xml_node& r) const
4016 {
4017 return (_root >= r._root);
4018 }
4019
4020 PUGI__FN bool xml_node::empty() const
4021 {
4022 return !_root;
4023 }
4024
4025 PUGI__FN const char_t* xml_node::name() const
4026 {
4027 return (_root && _root->name) ? _root->name : PUGIXML_TEXT("");
4028 }
4029
4030 PUGI__FN xml_node_type xml_node::type() const
4031 {
4032 return _root ? static_cast<xml_node_type>((_root->header & impl::xml_memory_page_type_mask) + 1) : node_null;
4033 }
4034
4035 PUGI__FN const char_t* xml_node::value() const
4036 {
4037 return (_root && _root->value) ? _root->value : PUGIXML_TEXT("");
4038 }
4039
4040 PUGI__FN xml_node xml_node::child(const char_t* name_) const
4041 {
4042 if (!_root) return xml_node();
4043
4044 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
4045 if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
4046
4047 return xml_node();
4048 }
4049
4050 PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const
4051 {
4052 if (!_root) return xml_attribute();
4053
4054 for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
4055 if (i->name && impl::strequal(name_, i->name))
4056 return xml_attribute(i);
4057
4058 return xml_attribute();
4059 }
4060
4061 PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const
4062 {
4063 if (!_root) return xml_node();
4064
4065 for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
4066 if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
4067
4068 return xml_node();
4069 }
4070
4071 PUGI__FN xml_node xml_node::next_sibling() const
4072 {
4073 if (!_root) return xml_node();
4074
4075 if (_root->next_sibling) return xml_node(_root->next_sibling);
4076 else return xml_node();
4077 }
4078
4079 PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const
4080 {
4081 if (!_root) return xml_node();
4082
4083 for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)
4084 if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
4085
4086 return xml_node();
4087 }
4088
4089 PUGI__FN xml_node xml_node::previous_sibling() const
4090 {
4091 if (!_root) return xml_node();
4092
4093 if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c);
4094 else return xml_node();
4095 }
4096
4097 PUGI__FN xml_node xml_node::parent() const
4098 {
4099 return _root ? xml_node(_root->parent) : xml_node();
4100 }
4101
4102 PUGI__FN xml_node xml_node::root() const
4103 {
4104 if (!_root) return xml_node();
4105
4106 impl::xml_memory_page* page = reinterpret_cast<impl::xml_memory_page*>(_root->header & impl::xml_memory_page_pointer_mask);
4107
4108 return xml_node(static_cast<impl::xml_document_struct*>(page->allocator));
4109 }
4110
4111 PUGI__FN xml_text xml_node::text() const
4112 {
4113 return xml_text(_root);
4114 }
4115
4116 PUGI__FN const char_t* xml_node::child_value() const
4117 {
4118 if (!_root) return PUGIXML_TEXT("");
4119
4120 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
4121 if (i->value && impl::is_text_node(i))
4122 return i->value;
4123
4124 return PUGIXML_TEXT("");
4125 }
4126
4127 PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const
4128 {
4129 return child(name_).child_value();
4130 }
4131
4132 PUGI__FN xml_attribute xml_node::first_attribute() const
4133 {
4134 return _root ? xml_attribute(_root->first_attribute) : xml_attribute();
4135 }
4136
4137 PUGI__FN xml_attribute xml_node::last_attribute() const
4138 {
4139 return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute();
4140 }
4141
4142 PUGI__FN xml_node xml_node::first_child() const
4143 {
4144 return _root ? xml_node(_root->first_child) : xml_node();
4145 }
4146
4147 PUGI__FN xml_node xml_node::last_child() const
4148 {
4149 return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node();
4150 }
4151
4152 PUGI__FN bool xml_node::set_name(const char_t* rhs)
4153 {
4154 switch (type())
4155 {
4156 case node_pi:
4157 case node_declaration:
4158 case node_element:
4159 return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs);
4160
4161 default:
4162 return false;
4163 }
4164 }
4165
4166 PUGI__FN bool xml_node::set_value(const char_t* rhs)
4167 {
4168 switch (type())
4169 {
4170 case node_pi:
4171 case node_cdata:
4172 case node_pcdata:
4173 case node_comment:
4174 case node_doctype:
4175 return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs);
4176
4177 default:
4178 return false;
4179 }
4180 }
4181
4182 PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_)
4183 {
4184 if (type() != node_element && type() != node_declaration) return xml_attribute();
4185
4186 xml_attribute a(impl::append_attribute_ll(_root, impl::get_allocator(_root)));
4187 a.set_name(name_);
4188
4189 return a;
4190 }
4191
4192 PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_)
4193 {
4194 if (type() != node_element && type() != node_declaration) return xml_attribute();
4195
4196 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
4197 if (!a) return xml_attribute();
4198
4199 a.set_name(name_);
4200
4201 xml_attribute_struct* head = _root->first_attribute;
4202
4203 if (head)
4204 {
4205 a._attr->prev_attribute_c = head->prev_attribute_c;
4206 head->prev_attribute_c = a._attr;
4207 }
4208 else
4209 a._attr->prev_attribute_c = a._attr;
4210
4211 a._attr->next_attribute = head;
4212 _root->first_attribute = a._attr;
4213
4214 return a;
4215 }
4216
4217 PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr)
4218 {
4219 if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute();
4220
4221 // check that attribute belongs to *this
4222 xml_attribute_struct* cur = attr._attr;
4223
4224 while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c;
4225
4226 if (cur != _root->first_attribute) return xml_attribute();
4227
4228 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
4229 if (!a) return xml_attribute();
4230
4231 a.set_name(name_);
4232
4233 if (attr._attr->prev_attribute_c->next_attribute)
4234 attr._attr->prev_attribute_c->next_attribute = a._attr;
4235 else
4236 _root->first_attribute = a._attr;
4237
4238 a._attr->prev_attribute_c = attr._attr->prev_attribute_c;
4239 a._attr->next_attribute = attr._attr;
4240 attr._attr->prev_attribute_c = a._attr;
4241
4242 return a;
4243 }
4244
4245 PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr)
4246 {
4247 if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute();
4248
4249 // check that attribute belongs to *this
4250 xml_attribute_struct* cur = attr._attr;
4251
4252 while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c;
4253
4254 if (cur != _root->first_attribute) return xml_attribute();
4255
4256 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
4257 if (!a) return xml_attribute();
4258
4259 a.set_name(name_);
4260
4261 if (attr._attr->next_attribute)
4262 attr._attr->next_attribute->prev_attribute_c = a._attr;
4263 else
4264 _root->first_attribute->prev_attribute_c = a._attr;
4265
4266 a._attr->next_attribute = attr._attr->next_attribute;
4267 a._attr->prev_attribute_c = attr._attr;
4268 attr._attr->next_attribute = a._attr;
4269
4270 return a;
4271 }
4272
4273 PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto)
4274 {
4275 if (!proto) return xml_attribute();
4276
4277 xml_attribute result = append_attribute(proto.name());
4278 result.set_value(proto.value());
4279
4280 return result;
4281 }
4282
4283 PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto)
4284 {
4285 if (!proto) return xml_attribute();
4286
4287 xml_attribute result = prepend_attribute(proto.name());
4288 result.set_value(proto.value());
4289
4290 return result;
4291 }
4292
4293 PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr)
4294 {
4295 if (!proto) return xml_attribute();
4296
4297 xml_attribute result = insert_attribute_after(proto.name(), attr);
4298 result.set_value(proto.value());
4299
4300 return result;
4301 }
4302
4303 PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr)
4304 {
4305 if (!proto) return xml_attribute();
4306
4307 xml_attribute result = insert_attribute_before(proto.name(), attr);
4308 result.set_value(proto.value());
4309
4310 return result;
4311 }
4312
4313 PUGI__FN xml_node xml_node::append_child(xml_node_type type_)
4314 {
4315 if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
4316
4317 xml_node n(impl::append_node(_root, impl::get_allocator(_root), type_));
4318
4319 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
4320
4321 return n;
4322 }
4323
4324 PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_)
4325 {
4326 if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
4327
4328 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
4329 if (!n) return xml_node();
4330
4331 n._root->parent = _root;
4332
4333 xml_node_struct* head = _root->first_child;
4334
4335 if (head)
4336 {
4337 n._root->prev_sibling_c = head->prev_sibling_c;
4338 head->prev_sibling_c = n._root;
4339 }
4340 else
4341 n._root->prev_sibling_c = n._root;
4342
4343 n._root->next_sibling = head;
4344 _root->first_child = n._root;
4345
4346 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
4347
4348 return n;
4349 }
4350
4351 PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node)
4352 {
4353 if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
4354 if (!node._root || node._root->parent != _root) return xml_node();
4355
4356 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
4357 if (!n) return xml_node();
4358
4359 n._root->parent = _root;
4360
4361 if (node._root->prev_sibling_c->next_sibling)
4362 node._root->prev_sibling_c->next_sibling = n._root;
4363 else
4364 _root->first_child = n._root;
4365
4366 n._root->prev_sibling_c = node._root->prev_sibling_c;
4367 n._root->next_sibling = node._root;
4368 node._root->prev_sibling_c = n._root;
4369
4370 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
4371
4372 return n;
4373 }
4374
4375 PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node)
4376 {
4377 if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
4378 if (!node._root || node._root->parent != _root) return xml_node();
4379
4380 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
4381 if (!n) return xml_node();
4382
4383 n._root->parent = _root;
4384
4385 if (node._root->next_sibling)
4386 node._root->next_sibling->prev_sibling_c = n._root;
4387 else
4388 _root->first_child->prev_sibling_c = n._root;
4389
4390 n._root->next_sibling = node._root->next_sibling;
4391 n._root->prev_sibling_c = node._root;
4392 node._root->next_sibling = n._root;
4393
4394 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
4395
4396 return n;
4397 }
4398
4399 PUGI__FN xml_node xml_node::append_child(const char_t* name_)
4400 {
4401 xml_node result = append_child(node_element);
4402
4403 result.set_name(name_);
4404
4405 return result;
4406 }
4407
4408 PUGI__FN xml_node xml_node::prepend_child(const char_t* name_)
4409 {
4410 xml_node result = prepend_child(node_element);
4411
4412 result.set_name(name_);
4413
4414 return result;
4415 }
4416
4417 PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node)
4418 {
4419 xml_node result = insert_child_after(node_element, node);
4420
4421 result.set_name(name_);
4422
4423 return result;
4424 }
4425
4426 PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node)
4427 {
4428 xml_node result = insert_child_before(node_element, node);
4429
4430 result.set_name(name_);
4431
4432 return result;
4433 }
4434
4435 PUGI__FN xml_node xml_node::append_copy(const xml_node& proto)
4436 {
4437 xml_node result = append_child(proto.type());
4438
4439 if (result) impl::recursive_copy_skip(result, proto, result);
4440
4441 return result;
4442 }
4443
4444 PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto)
4445 {
4446 xml_node result = prepend_child(proto.type());
4447
4448 if (result) impl::recursive_copy_skip(result, proto, result);
4449
4450 return result;
4451 }
4452
4453 PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node)
4454 {
4455 xml_node result = insert_child_after(proto.type(), node);
4456
4457 if (result) impl::recursive_copy_skip(result, proto, result);
4458
4459 return result;
4460 }
4461
4462 PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node)
4463 {
4464 xml_node result = insert_child_before(proto.type(), node);
4465
4466 if (result) impl::recursive_copy_skip(result, proto, result);
4467
4468 return result;
4469 }
4470
4471 PUGI__FN bool xml_node::remove_attribute(const char_t* name_)
4472 {
4473 return remove_attribute(attribute(name_));
4474 }
4475
4476 PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a)
4477 {
4478 if (!_root || !a._attr) return false;
4479
4480 // check that attribute belongs to *this
4481 xml_attribute_struct* attr = a._attr;
4482
4483 while (attr->prev_attribute_c->next_attribute) attr = attr->prev_attribute_c;
4484
4485 if (attr != _root->first_attribute) return false;
4486
4487 if (a._attr->next_attribute) a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c;
4488 else if (_root->first_attribute) _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c;
4489
4490 if (a._attr->prev_attribute_c->next_attribute) a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute;
4491 else _root->first_attribute = a._attr->next_attribute;
4492
4493 impl::destroy_attribute(a._attr, impl::get_allocator(_root));
4494
4495 return true;
4496 }
4497
4498 PUGI__FN bool xml_node::remove_child(const char_t* name_)
4499 {
4500 return remove_child(child(name_));
4501 }
4502
4503 PUGI__FN bool xml_node::remove_child(const xml_node& n)
4504 {
4505 if (!_root || !n._root || n._root->parent != _root) return false;
4506
4507 if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c;
4508 else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c;
4509
4510 if (n._root->prev_sibling_c->next_sibling) n._root->prev_sibling_c->next_sibling = n._root->next_sibling;
4511 else _root->first_child = n._root->next_sibling;
4512
4513 impl::destroy_node(n._root, impl::get_allocator(_root));
4514
4515 return true;
4516 }
4517
4518 PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const
4519 {
4520 if (!_root) return xml_node();
4521
4522 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
4523 if (i->name && impl::strequal(name_, i->name))
4524 {
4525 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
4526 if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value))
4527 return xml_node(i);
4528 }
4529
4530 return xml_node();
4531 }
4532
4533 PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const
4534 {
4535 if (!_root) return xml_node();
4536
4537 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
4538 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
4539 if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value))
4540 return xml_node(i);
4541
4542 return xml_node();
4543 }
4544
4545#ifndef PUGIXML_NO_STL
4546 PUGI__FN string_t xml_node::path(char_t delimiter) const
4547 {
4548 xml_node cursor = *this; // Make a copy.
4549
4550 string_t result = cursor.name();
4551
4552 while (cursor.parent())
4553 {
4554 cursor = cursor.parent();
4555
4556 string_t temp = cursor.name();
4557 temp += delimiter;
4558 temp += result;
4559 result.swap(temp);
4560 }
4561
4562 return result;
4563 }
4564#endif
4565
4566 PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const
4567 {
4568 xml_node found = *this; // Current search context.
4569
4570 if (!_root || !path_ || !path_[0]) return found;
4571
4572 if (path_[0] == delimiter)
4573 {
4574 // Absolute path; e.g. '/foo/bar'
4575 found = found.root();
4576 ++path_;
4577 }
4578
4579 const char_t* path_segment = path_;
4580
4581 while (*path_segment == delimiter) ++path_segment;
4582
4583 const char_t* path_segment_end = path_segment;
4584
4585 while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end;
4586
4587 if (path_segment == path_segment_end) return found;
4588
4589 const char_t* next_segment = path_segment_end;
4590
4591 while (*next_segment == delimiter) ++next_segment;
4592
4593 if (*path_segment == '.' && path_segment + 1 == path_segment_end)
4594 return found.first_element_by_path(next_segment, delimiter);
4595 else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end)
4596 return found.parent().first_element_by_path(next_segment, delimiter);
4597 else
4598 {
4599 for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling)
4600 {
4601 if (j->name && impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
4602 {
4603 xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
4604
4605 if (subsearch) return subsearch;
4606 }
4607 }
4608
4609 return xml_node();
4610 }
4611 }
4612
4613 PUGI__FN bool xml_node::traverse(xml_tree_walker& walker)
4614 {
4615 walker._depth = -1;
4616
4617 xml_node arg_begin = *this;
4618 if (!walker.begin(arg_begin)) return false;
4619
4620 xml_node cur = first_child();
4621
4622 if (cur)
4623 {
4624 ++walker._depth;
4625
4626 do
4627 {
4628 xml_node arg_for_each = cur;
4629 if (!walker.for_each(arg_for_each))
4630 return false;
4631
4632 if (cur.first_child())
4633 {
4634 ++walker._depth;
4635 cur = cur.first_child();
4636 }
4637 else if (cur.next_sibling())
4638 cur = cur.next_sibling();
4639 else
4640 {
4641 // Borland C++ workaround
4642 while (!cur.next_sibling() && cur != *this && !cur.parent().empty())
4643 {
4644 --walker._depth;
4645 cur = cur.parent();
4646 }
4647
4648 if (cur != *this)
4649 cur = cur.next_sibling();
4650 }
4651 }
4652 while (cur && cur != *this);
4653 }
4654
4655 assert(walker._depth == -1);
4656
4657 xml_node arg_end = *this;
4658 return walker.end(arg_end);
4659 }
4660
4661 PUGI__FN size_t xml_node::hash_value() const
4662 {
4663 return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
4664 }
4665
4666 PUGI__FN xml_node_struct* xml_node::internal_object() const
4667 {
4668 return _root;
4669 }
4670
4671 PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
4672 {
4673 if (!_root) return;
4674
4675 impl::xml_buffered_writer buffered_writer(writer, encoding);
4676
4677 impl::node_output(buffered_writer, *this, indent, flags, depth);
4678 }
4679
4680#ifndef PUGIXML_NO_STL
4681 PUGI__FN void xml_node::print(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
4682 {
4683 xml_writer_stream writer(stream);
4684
4685 print(writer, indent, flags, encoding, depth);
4686 }
4687
4688 PUGI__FN void xml_node::print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const
4689 {
4690 xml_writer_stream writer(stream);
4691
4692 print(writer, indent, flags, encoding_wchar, depth);
4693 }
4694#endif
4695
4696 PUGI__FN ptrdiff_t xml_node::offset_debug() const
4697 {
4698 xml_node_struct* r = root()._root;
4699
4700 if (!r) return -1;
4701
4702 const char_t* buffer = static_cast<impl::xml_document_struct*>(r)->buffer;
4703
4704 if (!buffer) return -1;
4705
4706 switch (type())
4707 {
4708 case node_document:
4709 return 0;
4710
4711 case node_element:
4712 case node_declaration:
4713 case node_pi:
4714 return (_root->header & impl::xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer;
4715
4716 case node_pcdata:
4717 case node_cdata:
4718 case node_comment:
4719 case node_doctype:
4720 return (_root->header & impl::xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer;
4721
4722 default:
4723 return -1;
4724 }
4725 }
4726
4727#ifdef __BORLANDC__
4728 PUGI__FN bool operator&&(const xml_node& lhs, bool rhs)
4729 {
4730 return (bool)lhs && rhs;
4731 }
4732
4733 PUGI__FN bool operator||(const xml_node& lhs, bool rhs)
4734 {
4735 return (bool)lhs || rhs;
4736 }
4737#endif
4738
4739 PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root)
4740 {
4741 }
4742
4743 PUGI__FN xml_node_struct* xml_text::_data() const
4744 {
4745 if (!_root || impl::is_text_node(_root)) return _root;
4746
4747 for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)
4748 if (impl::is_text_node(node))
4749 return node;
4750
4751 return 0;
4752 }
4753
4754 PUGI__FN xml_node_struct* xml_text::_data_new()
4755 {
4756 xml_node_struct* d = _data();
4757 if (d) return d;
4758
4759 return xml_node(_root).append_child(node_pcdata).internal_object();
4760 }
4761
4762 PUGI__FN xml_text::xml_text(): _root(0)
4763 {
4764 }
4765
4766 PUGI__FN static void unspecified_bool_xml_text(xml_text***)
4767 {
4768 }
4769
4770 PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const
4771 {
4772 return _data() ? unspecified_bool_xml_text : 0;
4773 }
4774
4775 PUGI__FN bool xml_text::operator!() const
4776 {
4777 return !_data();
4778 }
4779
4780 PUGI__FN bool xml_text::empty() const
4781 {
4782 return _data() == 0;
4783 }
4784
4785 PUGI__FN const char_t* xml_text::get() const
4786 {
4787 xml_node_struct* d = _data();
4788
4789 return (d && d->value) ? d->value : PUGIXML_TEXT("");
4790 }
4791
4792 PUGI__FN const char_t* xml_text::as_string(const char_t* def) const
4793 {
4794 xml_node_struct* d = _data();
4795
4796 return (d && d->value) ? d->value : def;
4797 }
4798
4799 PUGI__FN int xml_text::as_int(int def) const
4800 {
4801 xml_node_struct* d = _data();
4802
4803 return impl::get_value_int(d ? d->value : 0, def);
4804 }
4805
4806 PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const
4807 {
4808 xml_node_struct* d = _data();
4809
4810 return impl::get_value_uint(d ? d->value : 0, def);
4811 }
4812
4813 PUGI__FN double xml_text::as_double(double def) const
4814 {
4815 xml_node_struct* d = _data();
4816
4817 return impl::get_value_double(d ? d->value : 0, def);
4818 }
4819
4820 PUGI__FN float xml_text::as_float(float def) const
4821 {
4822 xml_node_struct* d = _data();
4823
4824 return impl::get_value_float(d ? d->value : 0, def);
4825 }
4826
4827 PUGI__FN bool xml_text::as_bool(bool def) const
4828 {
4829 xml_node_struct* d = _data();
4830
4831 return impl::get_value_bool(d ? d->value : 0, def);
4832 }
4833
4834 PUGI__FN bool xml_text::set(const char_t* rhs)
4835 {
4836 xml_node_struct* dn = _data_new();
4837
4838 return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
4839 }
4840
4841 PUGI__FN bool xml_text::set(int rhs)
4842 {
4843 xml_node_struct* dn = _data_new();
4844
4845 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
4846 }
4847
4848 PUGI__FN bool xml_text::set(unsigned int rhs)
4849 {
4850 xml_node_struct* dn = _data_new();
4851
4852 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
4853 }
4854
4855 PUGI__FN bool xml_text::set(double rhs)
4856 {
4857 xml_node_struct* dn = _data_new();
4858
4859 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
4860 }
4861
4862 PUGI__FN bool xml_text::set(bool rhs)
4863 {
4864 xml_node_struct* dn = _data_new();
4865
4866 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
4867 }
4868
4869 PUGI__FN xml_text& xml_text::operator=(const char_t* rhs)
4870 {
4871 set(rhs);
4872 return *this;
4873 }
4874
4875 PUGI__FN xml_text& xml_text::operator=(int rhs)
4876 {
4877 set(rhs);
4878 return *this;
4879 }
4880
4881 PUGI__FN xml_text& xml_text::operator=(unsigned int rhs)
4882 {
4883 set(rhs);
4884 return *this;
4885 }
4886
4887 PUGI__FN xml_text& xml_text::operator=(double rhs)
4888 {
4889 set(rhs);
4890 return *this;
4891 }
4892
4893 PUGI__FN xml_text& xml_text::operator=(bool rhs)
4894 {
4895 set(rhs);
4896 return *this;
4897 }
4898
4899 PUGI__FN xml_node xml_text::data() const
4900 {
4901 return xml_node(_data());
4902 }
4903
4904#ifdef __BORLANDC__
4905 PUGI__FN bool operator&&(const xml_text& lhs, bool rhs)
4906 {
4907 return (bool)lhs && rhs;
4908 }
4909
4910 PUGI__FN bool operator||(const xml_text& lhs, bool rhs)
4911 {
4912 return (bool)lhs || rhs;
4913 }
4914#endif
4915
4916 PUGI__FN xml_node_iterator::xml_node_iterator()
4917 {
4918 }
4919
4920 PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent())
4921 {
4922 }
4923
4924 PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
4925 {
4926 }
4927
4928 PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const
4929 {
4930 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
4931 }
4932
4933 PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const
4934 {
4935 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
4936 }
4937
4938 PUGI__FN xml_node& xml_node_iterator::operator*() const
4939 {
4940 assert(_wrap._root);
4941 return _wrap;
4942 }
4943
4944 PUGI__FN xml_node* xml_node_iterator::operator->() const
4945 {
4946 assert(_wrap._root);
4947 return const_cast<xml_node*>(&_wrap); // BCC32 workaround
4948 }
4949
4950 PUGI__FN const xml_node_iterator& xml_node_iterator::operator++()
4951 {
4952 assert(_wrap._root);
4953 _wrap._root = _wrap._root->next_sibling;
4954 return *this;
4955 }
4956
4957 PUGI__FN xml_node_iterator xml_node_iterator::operator++(int)
4958 {
4959 xml_node_iterator temp = *this;
4960 ++*this;
4961 return temp;
4962 }
4963
4964 PUGI__FN const xml_node_iterator& xml_node_iterator::operator--()
4965 {
4966 _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();
4967 return *this;
4968 }
4969
4970 PUGI__FN xml_node_iterator xml_node_iterator::operator--(int)
4971 {
4972 xml_node_iterator temp = *this;
4973 --*this;
4974 return temp;
4975 }
4976
4977 PUGI__FN xml_attribute_iterator::xml_attribute_iterator()
4978 {
4979 }
4980
4981 PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)
4982 {
4983 }
4984
4985 PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
4986 {
4987 }
4988
4989 PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const
4990 {
4991 return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
4992 }
4993
4994 PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const
4995 {
4996 return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
4997 }
4998
4999 PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const
5000 {
5001 assert(_wrap._attr);
5002 return _wrap;
5003 }
5004
5005 PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const
5006 {
5007 assert(_wrap._attr);
5008 return const_cast<xml_attribute*>(&_wrap); // BCC32 workaround
5009 }
5010
5011 PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++()
5012 {
5013 assert(_wrap._attr);
5014 _wrap._attr = _wrap._attr->next_attribute;
5015 return *this;
5016 }
5017
5018 PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int)
5019 {
5020 xml_attribute_iterator temp = *this;
5021 ++*this;
5022 return temp;
5023 }
5024
5025 PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--()
5026 {
5027 _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();
5028 return *this;
5029 }
5030
5031 PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int)
5032 {
5033 xml_attribute_iterator temp = *this;
5034 --*this;
5035 return temp;
5036 }
5037
5038 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0)
5039 {
5040 }
5041
5042 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _node(node), _name(name)
5043 {
5044 }
5045
5046 PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const
5047 {
5048 return _node == rhs._node;
5049 }
5050
5051 PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const
5052 {
5053 return _node != rhs._node;
5054 }
5055
5056 PUGI__FN xml_node& xml_named_node_iterator::operator*() const
5057 {
5058 assert(_node._root);
5059 return _node;
5060 }
5061
5062 PUGI__FN xml_node* xml_named_node_iterator::operator->() const
5063 {
5064 assert(_node._root);
5065 return const_cast<xml_node*>(&_node); // BCC32 workaround
5066 }
5067
5068 PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++()
5069 {
5070 assert(_node._root);
5071 _node = _node.next_sibling(_name);
5072 return *this;
5073 }
5074
5075 PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int)
5076 {
5077 xml_named_node_iterator temp = *this;
5078 ++*this;
5079 return temp;
5080 }
5081
5082 PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)
5083 {
5084 }
5085
5086 PUGI__FN xml_parse_result::operator bool() const
5087 {
5088 return status == status_ok;
5089 }
5090
5091 PUGI__FN const char* xml_parse_result::description() const
5092 {
5093 switch (status)
5094 {
5095 case status_ok: return "No error";
5096
5097 case status_file_not_found: return "File was not found";
5098 case status_io_error: return "Error reading from file/stream";
5099 case status_out_of_memory: return "Could not allocate memory";
5100 case status_internal_error: return "Internal error occurred";
5101
5102 case status_unrecognized_tag: return "Could not determine tag type";
5103
5104 case status_bad_pi: return "Error parsing document declaration/processing instruction";
5105 case status_bad_comment: return "Error parsing comment";
5106 case status_bad_cdata: return "Error parsing CDATA section";
5107 case status_bad_doctype: return "Error parsing document type declaration";
5108 case status_bad_pcdata: return "Error parsing PCDATA section";
5109 case status_bad_start_element: return "Error parsing start element tag";
5110 case status_bad_attribute: return "Error parsing element attribute";
5111 case status_bad_end_element: return "Error parsing end element tag";
5112 case status_end_element_mismatch: return "Start-end tags mismatch";
5113
5114 default: return "Unknown error";
5115 }
5116 }
5117
5118 PUGI__FN xml_document::xml_document(): _buffer(0)
5119 {
5120 create();
5121 }
5122
5123 PUGI__FN xml_document::~xml_document()
5124 {
5125 destroy();
5126 }
5127
5128 PUGI__FN void xml_document::reset()
5129 {
5130 destroy();
5131 create();
5132 }
5133
5134 PUGI__FN void xml_document::reset(const xml_document& proto)
5135 {
5136 reset();
5137
5138 for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling())
5139 append_copy(cur);
5140 }
5141
5142 PUGI__FN void xml_document::create()
5143 {
5144 // initialize sentinel page
5145 PUGI__STATIC_ASSERT(offsetof(impl::xml_memory_page, data) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment <= sizeof(_memory));
5146
5147 // align upwards to page boundary
5148 void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1));
5149
5150 // prepare page structure
5151 impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory);
5152
5153 page->busy_size = impl::xml_memory_page_size;
5154
5155 // allocate new root
5156 _root = new (page->data) impl::xml_document_struct(page);
5157 _root->prev_sibling_c = _root;
5158
5159 // setup sentinel page
5160 page->allocator = static_cast<impl::xml_document_struct*>(_root);
5161 }
5162
5163 PUGI__FN void xml_document::destroy()
5164 {
5165 // destroy static storage
5166 if (_buffer)
5167 {
5168 impl::xml_memory::deallocate(_buffer);
5169 _buffer = 0;
5170 }
5171
5172 // destroy dynamic storage, leave sentinel page (it's in static memory)
5173 if (_root)
5174 {
5175 impl::xml_memory_page* root_page = reinterpret_cast<impl::xml_memory_page*>(_root->header & impl::xml_memory_page_pointer_mask);
5176 assert(root_page && !root_page->prev && !root_page->memory);
5177
5178 // destroy all pages
5179 for (impl::xml_memory_page* page = root_page->next; page; )
5180 {
5181 impl::xml_memory_page* next = page->next;
5182
5183 impl::xml_allocator::deallocate_page(page);
5184
5185 page = next;
5186 }
5187
5188 // cleanup root page
5189 root_page->allocator = 0;
5190 root_page->next = 0;
5191 root_page->busy_size = root_page->freed_size = 0;
5192
5193 _root = 0;
5194 }
5195 }
5196
5197#ifndef PUGIXML_NO_STL
5198 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding)
5199 {
5200 reset();
5201
5202 return impl::load_stream_impl(*this, stream, options, encoding);
5203 }
5204
5205 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)
5206 {
5207 reset();
5208
5209 return impl::load_stream_impl(*this, stream, options, encoding_wchar);
5210 }
5211#endif
5212
5213 PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
5214 {
5215 // Force native encoding (skip autodetection)
5216 #ifdef PUGIXML_WCHAR_MODE
5217 xml_encoding encoding = encoding_wchar;
5218 #else
5219 xml_encoding encoding = encoding_utf8;
5220 #endif
5221
5222 return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding);
5223 }
5224
5225 PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding)
5226 {
5227 reset();
5228
5229 FILE* file = fopen(path_, "rb");
5230
5231 return impl::load_file_impl(*this, file, options, encoding);
5232 }
5233
5234 PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding)
5235 {
5236 reset();
5237
5238 FILE* file = impl::open_file_wide(path_, L"rb");
5239
5240 return impl::load_file_impl(*this, file, options, encoding);
5241 }
5242
5243 PUGI__FN xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own)
5244 {
5245 reset();
5246
5247 // check input buffer
5248 assert(contents || size == 0);
5249
5250 // get actual encoding
5251 xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
5252
5253 // get private buffer
5254 char_t* buffer = 0;
5255 size_t length = 0;
5256
5257 if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);
5258
5259 // delete original buffer if we performed a conversion
5260 if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
5261
5262 // parse
5263 xml_parse_result res = impl::xml_parser::parse(buffer, length, _root, options);
5264
5265 // remember encoding
5266 res.encoding = buffer_encoding;
5267
5268 // grab onto buffer if it's our buffer, user is responsible for deallocating contens himself
5269 if (own || buffer != contents) _buffer = buffer;
5270
5271 return res;
5272 }
5273
5274 PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
5275 {
5276 return load_buffer_impl(const_cast<void*>(contents), size, options, encoding, false, false);
5277 }
5278
5279 PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding)
5280 {
5281 return load_buffer_impl(contents, size, options, encoding, true, false);
5282 }
5283
5284 PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding)
5285 {
5286 return load_buffer_impl(contents, size, options, encoding, true, true);
5287 }
5288
5289 PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const
5290 {
5291 impl::xml_buffered_writer buffered_writer(writer, encoding);
5292
5293 if ((flags & format_write_bom) && encoding != encoding_latin1)
5294 {
5295 // BOM always represents the codepoint U+FEFF, so just write it in native encoding
5296 #ifdef PUGIXML_WCHAR_MODE
5297 unsigned int bom = 0xfeff;
5298 buffered_writer.write(static_cast<wchar_t>(bom));
5299 #else
5300 buffered_writer.write('\xef', '\xbb', '\xbf');
5301 #endif
5302 }
5303
5304 if (!(flags & format_no_declaration) && !impl::has_declaration(*this))
5305 {
5306 buffered_writer.write(PUGIXML_TEXT("<?xml version=\"1.0\""));
5307 if (encoding == encoding_latin1) buffered_writer.write(PUGIXML_TEXT(" encoding=\"ISO-8859-1\""));
5308 buffered_writer.write('?', '>');
5309 if (!(flags & format_raw)) buffered_writer.write('\n');
5310 }
5311
5312 impl::node_output(buffered_writer, *this, indent, flags, 0);
5313 }
5314
5315#ifndef PUGIXML_NO_STL
5316 PUGI__FN void xml_document::save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const
5317 {
5318 xml_writer_stream writer(stream);
5319
5320 save(writer, indent, flags, encoding);
5321 }
5322
5323 PUGI__FN void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags) const
5324 {
5325 xml_writer_stream writer(stream);
5326
5327 save(writer, indent, flags, encoding_wchar);
5328 }
5329#endif
5330
5331 PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
5332 {
5333 FILE* file = fopen(path_, (flags & format_save_file_text) ? "w" : "wb");
5334 return impl::save_file_impl(*this, file, indent, flags, encoding);
5335 }
5336
5337 PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
5338 {
5339 FILE* file = impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb");
5340 return impl::save_file_impl(*this, file, indent, flags, encoding);
5341 }
5342
5343 PUGI__FN xml_node xml_document::document_element() const
5344 {
5345 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5346 if ((i->header & impl::xml_memory_page_type_mask) + 1 == node_element)
5347 return xml_node(i);
5348
5349 return xml_node();
5350 }
5351
5352#ifndef PUGIXML_NO_STL
5353 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)
5354 {
5355 assert(str);
5356
5357 return impl::as_utf8_impl(str, wcslen(str));
5358 }
5359
5360 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str)
5361 {
5362 return impl::as_utf8_impl(str.c_str(), str.size());
5363 }
5364
5365 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str)
5366 {
5367 assert(str);
5368
5369 return impl::as_wide_impl(str, strlen(str));
5370 }
5371
5372 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str)
5373 {
5374 return impl::as_wide_impl(str.c_str(), str.size());
5375 }
5376#endif
5377
5378 PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
5379 {
5380 impl::xml_memory::allocate = allocate;
5381 impl::xml_memory::deallocate = deallocate;
5382 }
5383
5384 PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
5385 {
5386 return impl::xml_memory::allocate;
5387 }
5388
5389 PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
5390 {
5391 return impl::xml_memory::deallocate;
5392 }
5393}
5394
5395#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
5396namespace std
5397{
5398 // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
5399 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&)
5400 {
5401 return std::bidirectional_iterator_tag();
5402 }
5403
5404 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&)
5405 {
5406 return std::bidirectional_iterator_tag();
5407 }
5408
5409 PUGI__FN std::forward_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&)
5410 {
5411 return std::forward_iterator_tag();
5412 }
5413}
5414#endif
5415
5416#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
5417namespace std
5418{
5419 // Workarounds for (non-standard) iterator category detection
5420 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&)
5421 {
5422 return std::bidirectional_iterator_tag();
5423 }
5424
5425 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&)
5426 {
5427 return std::bidirectional_iterator_tag();
5428 }
5429
5430 PUGI__FN std::forward_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&)
5431 {
5432 return std::forward_iterator_tag();
5433 }
5434}
5435#endif
5436
5437#ifndef PUGIXML_NO_XPATH
5438
5439// STL replacements
5440PUGI__NS_BEGIN
5441 struct equal_to
5442 {
5443 template <typename T> bool operator()(const T& lhs, const T& rhs) const
5444 {
5445 return lhs == rhs;
5446 }
5447 };
5448
5449 struct not_equal_to
5450 {
5451 template <typename T> bool operator()(const T& lhs, const T& rhs) const
5452 {
5453 return lhs != rhs;
5454 }
5455 };
5456
5457 struct less
5458 {
5459 template <typename T> bool operator()(const T& lhs, const T& rhs) const
5460 {
5461 return lhs < rhs;
5462 }
5463 };
5464
5465 struct less_equal
5466 {
5467 template <typename T> bool operator()(const T& lhs, const T& rhs) const
5468 {
5469 return lhs <= rhs;
5470 }
5471 };
5472
5473 template <typename T> void swap(T& lhs, T& rhs)
5474 {
5475 T temp = lhs;
5476 lhs = rhs;
5477 rhs = temp;
5478 }
5479
5480 template <typename I, typename Pred> I min_element(I begin, I end, const Pred& pred)
5481 {
5482 I result = begin;
5483
5484 for (I it = begin + 1; it != end; ++it)
5485 if (pred(*it, *result))
5486 result = it;
5487
5488 return result;
5489 }
5490
5491 template <typename I> void reverse(I begin, I end)
5492 {
5493 while (begin + 1 < end) swap(*begin++, *--end);
5494 }
5495
5496 template <typename I> I unique(I begin, I end)
5497 {
5498 // fast skip head
5499 while (begin + 1 < end && *begin != *(begin + 1)) begin++;
5500
5501 if (begin == end) return begin;
5502
5503 // last written element
5504 I write = begin++;
5505
5506 // merge unique elements
5507 while (begin != end)
5508 {
5509 if (*begin != *write)
5510 *++write = *begin++;
5511 else
5512 begin++;
5513 }
5514
5515 // past-the-end (write points to live element)
5516 return write + 1;
5517 }
5518
5519 template <typename I> void copy_backwards(I begin, I end, I target)
5520 {
5521 while (begin != end) *--target = *--end;
5522 }
5523
5524 template <typename I, typename Pred, typename T> void insertion_sort(I begin, I end, const Pred& pred, T*)
5525 {
5526 assert(begin != end);
5527
5528 for (I it = begin + 1; it != end; ++it)
5529 {
5530 T val = *it;
5531
5532 if (pred(val, *begin))
5533 {
5534 // move to front
5535 copy_backwards(begin, it, it + 1);
5536 *begin = val;
5537 }
5538 else
5539 {
5540 I hole = it;
5541
5542 // move hole backwards
5543 while (pred(val, *(hole - 1)))
5544 {
5545 *hole = *(hole - 1);
5546 hole--;
5547 }
5548
5549 // fill hole with element
5550 *hole = val;
5551 }
5552 }
5553 }
5554
5555 // std variant for elements with ==
5556 template <typename I, typename Pred> void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend)
5557 {
5558 I eqbeg = middle, eqend = middle + 1;
5559
5560 // expand equal range
5561 while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg;
5562 while (eqend != end && *eqend == *eqbeg) ++eqend;
5563
5564 // process outer elements
5565 I ltend = eqbeg, gtbeg = eqend;
5566
5567 for (;;)
5568 {
5569 // find the element from the right side that belongs to the left one
5570 for (; gtbeg != end; ++gtbeg)
5571 if (!pred(*eqbeg, *gtbeg))
5572 {
5573 if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++);
5574 else break;
5575 }
5576
5577 // find the element from the left side that belongs to the right one
5578 for (; ltend != begin; --ltend)
5579 if (!pred(*(ltend - 1), *eqbeg))
5580 {
5581 if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg);
5582 else break;
5583 }
5584
5585 // scanned all elements
5586 if (gtbeg == end && ltend == begin)
5587 {
5588 *out_eqbeg = eqbeg;
5589 *out_eqend = eqend;
5590 return;
5591 }
5592
5593 // make room for elements by moving equal area
5594 if (gtbeg == end)
5595 {
5596 if (--ltend != --eqbeg) swap(*ltend, *eqbeg);
5597 swap(*eqbeg, *--eqend);
5598 }
5599 else if (ltend == begin)
5600 {
5601 if (eqend != gtbeg) swap(*eqbeg, *eqend);
5602 ++eqend;
5603 swap(*gtbeg++, *eqbeg++);
5604 }
5605 else swap(*gtbeg++, *--ltend);
5606 }
5607 }
5608
5609 template <typename I, typename Pred> void median3(I first, I middle, I last, const Pred& pred)
5610 {
5611 if (pred(*middle, *first)) swap(*middle, *first);
5612 if (pred(*last, *middle)) swap(*last, *middle);
5613 if (pred(*middle, *first)) swap(*middle, *first);
5614 }
5615
5616 template <typename I, typename Pred> void median(I first, I middle, I last, const Pred& pred)
5617 {
5618 if (last - first <= 40)
5619 {
5620 // median of three for small chunks
5621 median3(first, middle, last, pred);
5622 }
5623 else
5624 {
5625 // median of nine
5626 size_t step = (last - first + 1) / 8;
5627
5628 median3(first, first + step, first + 2 * step, pred);
5629 median3(middle - step, middle, middle + step, pred);
5630 median3(last - 2 * step, last - step, last, pred);
5631 median3(first + step, middle, last - step, pred);
5632 }
5633 }
5634
5635 template <typename I, typename Pred> void sort(I begin, I end, const Pred& pred)
5636 {
5637 // sort large chunks
5638 while (end - begin > 32)
5639 {
5640 // find median element
5641 I middle = begin + (end - begin) / 2;
5642 median(begin, middle, end - 1, pred);
5643
5644 // partition in three chunks (< = >)
5645 I eqbeg, eqend;
5646 partition(begin, middle, end, pred, &eqbeg, &eqend);
5647
5648 // loop on larger half
5649 if (eqbeg - begin > end - eqend)
5650 {
5651 sort(eqend, end, pred);
5652 end = eqbeg;
5653 }
5654 else
5655 {
5656 sort(begin, eqbeg, pred);
5657 begin = eqend;
5658 }
5659 }
5660
5661 // insertion sort small chunk
5662 if (begin != end) insertion_sort(begin, end, pred, &*begin);
5663 }
5664PUGI__NS_END
5665
5666// Allocator used for AST and evaluation stacks
5667PUGI__NS_BEGIN
5668 struct xpath_memory_block
5669 {
5670 xpath_memory_block* next;
5671
5672 char data[
5673 #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
5674 PUGIXML_MEMORY_XPATH_PAGE_SIZE
5675 #else
5676 4096
5677 #endif
5678 ];
5679 };
5680
5681 class xpath_allocator
5682 {
5683 xpath_memory_block* _root;
5684 size_t _root_size;
5685
5686 public:
5687 #ifdef PUGIXML_NO_EXCEPTIONS
5688 jmp_buf* error_handler;
5689 #endif
5690
5691 xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size)
5692 {
5693 #ifdef PUGIXML_NO_EXCEPTIONS
5694 error_handler = 0;
5695 #endif
5696 }
5697
5698 void* allocate_nothrow(size_t size)
5699 {
5700 const size_t block_capacity = sizeof(_root->data);
5701
5702 // align size so that we're able to store pointers in subsequent blocks
5703 size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
5704
5705 if (_root_size + size <= block_capacity)
5706 {
5707 void* buf = _root->data + _root_size;
5708 _root_size += size;
5709 return buf;
5710 }
5711 else
5712 {
5713 size_t block_data_size = (size > block_capacity) ? size : block_capacity;
5714 size_t block_size = block_data_size + offsetof(xpath_memory_block, data);
5715
5716 xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size));
5717 if (!block) return 0;
5718
5719 block->next = _root;
5720
5721 _root = block;
5722 _root_size = size;
5723
5724 return block->data;
5725 }
5726 }
5727
5728 void* allocate(size_t size)
5729 {
5730 void* result = allocate_nothrow(size);
5731
5732 if (!result)
5733 {
5734 #ifdef PUGIXML_NO_EXCEPTIONS
5735 assert(error_handler);
5736 longjmp(*error_handler, 1);
5737 #else
5738 throw std::bad_alloc();
5739 #endif
5740 }
5741
5742 return result;
5743 }
5744
5745 void* reallocate(void* ptr, size_t old_size, size_t new_size)
5746 {
5747 // align size so that we're able to store pointers in subsequent blocks
5748 old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
5749 new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
5750
5751 // we can only reallocate the last object
5752 assert(ptr == 0 || static_cast<char*>(ptr) + old_size == _root->data + _root_size);
5753
5754 // adjust root size so that we have not allocated the object at all
5755 bool only_object = (_root_size == old_size);
5756
5757 if (ptr) _root_size -= old_size;
5758
5759 // allocate a new version (this will obviously reuse the memory if possible)
5760 void* result = allocate(new_size);
5761 assert(result);
5762
5763 // we have a new block
5764 if (result != ptr && ptr)
5765 {
5766 // copy old data
5767 assert(new_size > old_size);
5768 memcpy(result, ptr, old_size);
5769
5770 // free the previous page if it had no other objects
5771 if (only_object)
5772 {
5773 assert(_root->data == result);
5774 assert(_root->next);
5775
5776 xpath_memory_block* next = _root->next->next;
5777
5778 if (next)
5779 {
5780 // deallocate the whole page, unless it was the first one
5781 xml_memory::deallocate(_root->next);
5782 _root->next = next;
5783 }
5784 }
5785 }
5786
5787 return result;
5788 }
5789
5790 void revert(const xpath_allocator& state)
5791 {
5792 // free all new pages
5793 xpath_memory_block* cur = _root;
5794
5795 while (cur != state._root)
5796 {
5797 xpath_memory_block* next = cur->next;
5798
5799 xml_memory::deallocate(cur);
5800
5801 cur = next;
5802 }
5803
5804 // restore state
5805 _root = state._root;
5806 _root_size = state._root_size;
5807 }
5808
5809 void release()
5810 {
5811 xpath_memory_block* cur = _root;
5812 assert(cur);
5813
5814 while (cur->next)
5815 {
5816 xpath_memory_block* next = cur->next;
5817
5818 xml_memory::deallocate(cur);
5819
5820 cur = next;
5821 }
5822 }
5823 };
5824
5825 struct xpath_allocator_capture
5826 {
5827 xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc)
5828 {
5829 }
5830
5831 ~xpath_allocator_capture()
5832 {
5833 _target->revert(_state);
5834 }
5835
5836 xpath_allocator* _target;
5837 xpath_allocator _state;
5838 };
5839
5840 struct xpath_stack
5841 {
5842 xpath_allocator* result;
5843 xpath_allocator* temp;
5844 };
5845
5846 struct xpath_stack_data
5847 {
5848 xpath_memory_block blocks[2];
5849 xpath_allocator result;
5850 xpath_allocator temp;
5851 xpath_stack stack;
5852
5853 #ifdef PUGIXML_NO_EXCEPTIONS
5854 jmp_buf error_handler;
5855 #endif
5856
5857 xpath_stack_data(): result(blocks + 0), temp(blocks + 1)
5858 {
5859 blocks[0].next = blocks[1].next = 0;
5860
5861 stack.result = &result;
5862 stack.temp = &temp;
5863
5864 #ifdef PUGIXML_NO_EXCEPTIONS
5865 result.error_handler = temp.error_handler = &error_handler;
5866 #endif
5867 }
5868
5869 ~xpath_stack_data()
5870 {
5871 result.release();
5872 temp.release();
5873 }
5874 };
5875PUGI__NS_END
5876
5877// String class
5878PUGI__NS_BEGIN
5879 class xpath_string
5880 {
5881 const char_t* _buffer;
5882 bool _uses_heap;
5883
5884 static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc)
5885 {
5886 char_t* result = static_cast<char_t*>(alloc->allocate((length + 1) * sizeof(char_t)));
5887 assert(result);
5888
5889 memcpy(result, string, length * sizeof(char_t));
5890 result[length] = 0;
5891
5892 return result;
5893 }
5894
5895 static char_t* duplicate_string(const char_t* string, xpath_allocator* alloc)
5896 {
5897 return duplicate_string(string, strlength(string), alloc);
5898 }
5899
5900 public:
5901 xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false)
5902 {
5903 }
5904
5905 explicit xpath_string(const char_t* str, xpath_allocator* alloc)
5906 {
5907 bool empty_ = (*str == 0);
5908
5909 _buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(str, alloc);
5910 _uses_heap = !empty_;
5911 }
5912
5913 explicit xpath_string(const char_t* str, bool use_heap): _buffer(str), _uses_heap(use_heap)
5914 {
5915 }
5916
5917 xpath_string(const char_t* begin, const char_t* end, xpath_allocator* alloc)
5918 {
5919 assert(begin <= end);
5920
5921 bool empty_ = (begin == end);
5922
5923 _buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast<size_t>(end - begin), alloc);
5924 _uses_heap = !empty_;
5925 }
5926
5927 void append(const xpath_string& o, xpath_allocator* alloc)
5928 {
5929 // skip empty sources
5930 if (!*o._buffer) return;
5931
5932 // fast append for constant empty target and constant source
5933 if (!*_buffer && !_uses_heap && !o._uses_heap)
5934 {
5935 _buffer = o._buffer;
5936 }
5937 else
5938 {
5939 // need to make heap copy
5940 size_t target_length = strlength(_buffer);
5941 size_t source_length = strlength(o._buffer);
5942 size_t result_length = target_length + source_length;
5943
5944 // allocate new buffer
5945 char_t* result = static_cast<char_t*>(alloc->reallocate(_uses_heap ? const_cast<char_t*>(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t)));
5946 assert(result);
5947
5948 // append first string to the new buffer in case there was no reallocation
5949 if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t));
5950
5951 // append second string to the new buffer
5952 memcpy(result + target_length, o._buffer, source_length * sizeof(char_t));
5953 result[result_length] = 0;
5954
5955 // finalize
5956 _buffer = result;
5957 _uses_heap = true;
5958 }
5959 }
5960
5961 const char_t* c_str() const
5962 {
5963 return _buffer;
5964 }
5965
5966 size_t length() const
5967 {
5968 return strlength(_buffer);
5969 }
5970
5971 char_t* data(xpath_allocator* alloc)
5972 {
5973 // make private heap copy
5974 if (!_uses_heap)
5975 {
5976 _buffer = duplicate_string(_buffer, alloc);
5977 _uses_heap = true;
5978 }
5979
5980 return const_cast<char_t*>(_buffer);
5981 }
5982
5983 bool empty() const
5984 {
5985 return *_buffer == 0;
5986 }
5987
5988 bool operator==(const xpath_string& o) const
5989 {
5990 return strequal(_buffer, o._buffer);
5991 }
5992
5993 bool operator!=(const xpath_string& o) const
5994 {
5995 return !strequal(_buffer, o._buffer);
5996 }
5997
5998 bool uses_heap() const
5999 {
6000 return _uses_heap;
6001 }
6002 };
6003
6004 PUGI__FN xpath_string xpath_string_const(const char_t* str)
6005 {
6006 return xpath_string(str, false);
6007 }
6008PUGI__NS_END
6009
6010PUGI__NS_BEGIN
6011 PUGI__FN bool starts_with(const char_t* string, const char_t* pattern)
6012 {
6013 while (*pattern && *string == *pattern)
6014 {
6015 string++;
6016 pattern++;
6017 }
6018
6019 return *pattern == 0;
6020 }
6021
6022 PUGI__FN const char_t* find_char(const char_t* s, char_t c)
6023 {
6024 #ifdef PUGIXML_WCHAR_MODE
6025 return wcschr(s, c);
6026 #else
6027 return strchr(s, c);
6028 #endif
6029 }
6030
6031 PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p)
6032 {
6033 #ifdef PUGIXML_WCHAR_MODE
6034 // MSVC6 wcsstr bug workaround (if s is empty it always returns 0)
6035 return (*p == 0) ? s : wcsstr(s, p);
6036 #else
6037 return strstr(s, p);
6038 #endif
6039 }
6040
6041 // Converts symbol to lower case, if it is an ASCII one
6042 PUGI__FN char_t tolower_ascii(char_t ch)
6043 {
6044 return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch;
6045 }
6046
6047 PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)
6048 {
6049 if (na.attribute())
6050 return xpath_string_const(na.attribute().value());
6051 else
6052 {
6053 const xml_node& n = na.node();
6054
6055 switch (n.type())
6056 {
6057 case node_pcdata:
6058 case node_cdata:
6059 case node_comment:
6060 case node_pi:
6061 return xpath_string_const(n.value());
6062
6063 case node_document:
6064 case node_element:
6065 {
6066 xpath_string result;
6067
6068 xml_node cur = n.first_child();
6069
6070 while (cur && cur != n)
6071 {
6072 if (cur.type() == node_pcdata || cur.type() == node_cdata)
6073 result.append(xpath_string_const(cur.value()), alloc);
6074
6075 if (cur.first_child())
6076 cur = cur.first_child();
6077 else if (cur.next_sibling())
6078 cur = cur.next_sibling();
6079 else
6080 {
6081 while (!cur.next_sibling() && cur != n)
6082 cur = cur.parent();
6083
6084 if (cur != n) cur = cur.next_sibling();
6085 }
6086 }
6087
6088 return result;
6089 }
6090
6091 default:
6092 return xpath_string();
6093 }
6094 }
6095 }
6096
6097 PUGI__FN unsigned int node_height(xml_node n)
6098 {
6099 unsigned int result = 0;
6100
6101 while (n)
6102 {
6103 ++result;
6104 n = n.parent();
6105 }
6106
6107 return result;
6108 }
6109
6110 PUGI__FN bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh)
6111 {
6112 // normalize heights
6113 for (unsigned int i = rh; i < lh; i++) ln = ln.parent();
6114 for (unsigned int j = lh; j < rh; j++) rn = rn.parent();
6115
6116 // one node is the ancestor of the other
6117 if (ln == rn) return lh < rh;
6118
6119 // find common ancestor
6120 while (ln.parent() != rn.parent())
6121 {
6122 ln = ln.parent();
6123 rn = rn.parent();
6124 }
6125
6126 // there is no common ancestor (the shared parent is null), nodes are from different documents
6127 if (!ln.parent()) return ln < rn;
6128
6129 // determine sibling order
6130 for (; ln; ln = ln.next_sibling())
6131 if (ln == rn)
6132 return true;
6133
6134 return false;
6135 }
6136
6137 PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node)
6138 {
6139 while (node && node != parent) node = node.parent();
6140
6141 return parent && node == parent;
6142 }
6143
6144 PUGI__FN const void* document_order(const xpath_node& xnode)
6145 {
6146 xml_node_struct* node = xnode.node().internal_object();
6147
6148 if (node)
6149 {
6150 if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0) return node->name;
6151 if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0) return node->value;
6152 return 0;
6153 }
6154
6155 xml_attribute_struct* attr = xnode.attribute().internal_object();
6156
6157 if (attr)
6158 {
6159 if ((attr->header & xml_memory_page_name_allocated_mask) == 0) return attr->name;
6160 if ((attr->header & xml_memory_page_value_allocated_mask) == 0) return attr->value;
6161 return 0;
6162 }
6163
6164 return 0;
6165 }
6166
6167 struct document_order_comparator
6168 {
6169 bool operator()(const xpath_node& lhs, const xpath_node& rhs) const
6170 {
6171 // optimized document order based check
6172 const void* lo = document_order(lhs);
6173 const void* ro = document_order(rhs);
6174
6175 if (lo && ro) return lo < ro;
6176
6177 // slow comparison
6178 xml_node ln = lhs.node(), rn = rhs.node();
6179
6180 // compare attributes
6181 if (lhs.attribute() && rhs.attribute())
6182 {
6183 // shared parent
6184 if (lhs.parent() == rhs.parent())
6185 {
6186 // determine sibling order
6187 for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
6188 if (a == rhs.attribute())
6189 return true;
6190
6191 return false;
6192 }
6193
6194 // compare attribute parents
6195 ln = lhs.parent();
6196 rn = rhs.parent();
6197 }
6198 else if (lhs.attribute())
6199 {
6200 // attributes go after the parent element
6201 if (lhs.parent() == rhs.node()) return false;
6202
6203 ln = lhs.parent();
6204 }
6205 else if (rhs.attribute())
6206 {
6207 // attributes go after the parent element
6208 if (rhs.parent() == lhs.node()) return true;
6209
6210 rn = rhs.parent();
6211 }
6212
6213 if (ln == rn) return false;
6214
6215 unsigned int lh = node_height(ln);
6216 unsigned int rh = node_height(rn);
6217
6218 return node_is_before(ln, lh, rn, rh);
6219 }
6220 };
6221
6222 struct duplicate_comparator
6223 {
6224 bool operator()(const xpath_node& lhs, const xpath_node& rhs) const
6225 {
6226 if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true;
6227 else return rhs.attribute() ? false : lhs.node() < rhs.node();
6228 }
6229 };
6230
6231 PUGI__FN double gen_nan()
6232 {
6233 #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
6234 union { float f; uint32_t i; } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1];
6235 u[0].i = 0x7fc00000;
6236 return u[0].f;
6237 #else
6238 // fallback
6239 const volatile double zero = 0.0;
6240 return zero / zero;
6241 #endif
6242 }
6243
6244 PUGI__FN bool is_nan(double value)
6245 {
6246 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
6247 return !!_isnan(value);
6248 #elif defined(fpclassify) && defined(FP_NAN)
6249 return fpclassify(value) == FP_NAN;
6250 #else
6251 // fallback
6252 const volatile double v = value;
6253 return v != v;
6254 #endif
6255 }
6256
6257 PUGI__FN const char_t* convert_number_to_string_special(double value)
6258 {
6259 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
6260 if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0;
6261 if (_isnan(value)) return PUGIXML_TEXT("NaN");
6262 return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
6263 #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
6264 switch (fpclassify(value))
6265 {
6266 case FP_NAN:
6267 return PUGIXML_TEXT("NaN");
6268
6269 case FP_INFINITE:
6270 return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
6271
6272 case FP_ZERO:
6273 return PUGIXML_TEXT("0");
6274
6275 default:
6276 return 0;
6277 }
6278 #else
6279 // fallback
6280 const volatile double v = value;
6281
6282 if (v == 0) return PUGIXML_TEXT("0");
6283 if (v != v) return PUGIXML_TEXT("NaN");
6284 if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
6285 return 0;
6286 #endif
6287 }
6288
6289 PUGI__FN bool convert_number_to_boolean(double value)
6290 {
6291 return (value != 0 && !is_nan(value));
6292 }
6293
6294 PUGI__FN void truncate_zeros(char* begin, char* end)
6295 {
6296 while (begin != end && end[-1] == '0') end--;
6297
6298 *end = 0;
6299 }
6300
6301 // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent
6302#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
6303 PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)
6304 {
6305 // get base values
6306 int sign, exponent;
6307 _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign);
6308
6309 // truncate redundant zeros
6310 truncate_zeros(buffer, buffer + strlen(buffer));
6311
6312 // fill results
6313 *out_mantissa = buffer;
6314 *out_exponent = exponent;
6315 }
6316#else
6317 PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)
6318 {
6319 // get a scientific notation value with IEEE DBL_DIG decimals
6320 sprintf(buffer, "%.*e", DBL_DIG, value);
6321 assert(strlen(buffer) < buffer_size);
6322 (void)!buffer_size;
6323
6324 // get the exponent (possibly negative)
6325 char* exponent_string = strchr(buffer, 'e');
6326 assert(exponent_string);
6327
6328 int exponent = atoi(exponent_string + 1);
6329
6330 // extract mantissa string: skip sign
6331 char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer;
6332 assert(mantissa[0] != '0' && mantissa[1] == '.');
6333
6334 // divide mantissa by 10 to eliminate integer part
6335 mantissa[1] = mantissa[0];
6336 mantissa++;
6337 exponent++;
6338
6339 // remove extra mantissa digits and zero-terminate mantissa
6340 truncate_zeros(mantissa, exponent_string);
6341
6342 // fill results
6343 *out_mantissa = mantissa;
6344 *out_exponent = exponent;
6345 }
6346#endif
6347
6348 PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc)
6349 {
6350 // try special number conversion
6351 const char_t* special = convert_number_to_string_special(value);
6352 if (special) return xpath_string_const(special);
6353
6354 // get mantissa + exponent form
6355 char mantissa_buffer[64];
6356
6357 char* mantissa;
6358 int exponent;
6359 convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent);
6360
6361 // make the number!
6362 char_t result[512];
6363 char_t* s = result;
6364
6365 // sign
6366 if (value < 0) *s++ = '-';
6367
6368 // integer part
6369 if (exponent <= 0)
6370 {
6371 *s++ = '0';
6372 }
6373 else
6374 {
6375 while (exponent > 0)
6376 {
6377 assert(*mantissa == 0 || static_cast<unsigned int>(*mantissa - '0') <= 9);
6378 *s++ = *mantissa ? *mantissa++ : '0';
6379 exponent--;
6380 }
6381 }
6382
6383 // fractional part
6384 if (*mantissa)
6385 {
6386 // decimal point
6387 *s++ = '.';
6388
6389 // extra zeroes from negative exponent
6390 while (exponent < 0)
6391 {
6392 *s++ = '0';
6393 exponent++;
6394 }
6395
6396 // extra mantissa digits
6397 while (*mantissa)
6398 {
6399 assert(static_cast<unsigned int>(*mantissa - '0') <= 9);
6400 *s++ = *mantissa++;
6401 }
6402 }
6403
6404 // zero-terminate
6405 assert(s < result + sizeof(result) / sizeof(result[0]));
6406 *s = 0;
6407
6408 return xpath_string(result, alloc);
6409 }
6410
6411 PUGI__FN bool check_string_to_number_format(const char_t* string)
6412 {
6413 // parse leading whitespace
6414 while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
6415
6416 // parse sign
6417 if (*string == '-') ++string;
6418
6419 if (!*string) return false;
6420
6421 // if there is no integer part, there should be a decimal part with at least one digit
6422 if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false;
6423
6424 // parse integer part
6425 while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
6426
6427 // parse decimal part
6428 if (*string == '.')
6429 {
6430 ++string;
6431
6432 while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
6433 }
6434
6435 // parse trailing whitespace
6436 while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
6437
6438 return *string == 0;
6439 }
6440
6441 PUGI__FN double convert_string_to_number(const char_t* string)
6442 {
6443 // check string format
6444 if (!check_string_to_number_format(string)) return gen_nan();
6445
6446 // parse string
6447 #ifdef PUGIXML_WCHAR_MODE
6448 return wcstod(string, 0);
6449 #else
6450 return atof(string);
6451 #endif
6452 }
6453
6454 PUGI__FN bool convert_string_to_number(const char_t* begin, const char_t* end, double* out_result)
6455 {
6456 char_t buffer[32];
6457
6458 size_t length = static_cast<size_t>(end - begin);
6459 char_t* scratch = buffer;
6460
6461 if (length >= sizeof(buffer) / sizeof(buffer[0]))
6462 {
6463 // need to make dummy on-heap copy
6464 scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
6465 if (!scratch) return false;
6466 }
6467
6468 // copy string to zero-terminated buffer and perform conversion
6469 memcpy(scratch, begin, length * sizeof(char_t));
6470 scratch[length] = 0;
6471
6472 *out_result = convert_string_to_number(scratch);
6473
6474 // free dummy buffer
6475 if (scratch != buffer) xml_memory::deallocate(scratch);
6476
6477 return true;
6478 }
6479
6480 PUGI__FN double round_nearest(double value)
6481 {
6482 return floor(value + 0.5);
6483 }
6484
6485 PUGI__FN double round_nearest_nzero(double value)
6486 {
6487 // same as round_nearest, but returns -0 for [-0.5, -0]
6488 // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0)
6489 return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
6490 }
6491
6492 PUGI__FN const char_t* qualified_name(const xpath_node& node)
6493 {
6494 return node.attribute() ? node.attribute().name() : node.node().name();
6495 }
6496
6497 PUGI__FN const char_t* local_name(const xpath_node& node)
6498 {
6499 const char_t* name = qualified_name(node);
6500 const char_t* p = find_char(name, ':');
6501
6502 return p ? p + 1 : name;
6503 }
6504
6505 struct namespace_uri_predicate
6506 {
6507 const char_t* prefix;
6508 size_t prefix_length;
6509
6510 namespace_uri_predicate(const char_t* name)
6511 {
6512 const char_t* pos = find_char(name, ':');
6513
6514 prefix = pos ? name : 0;
6515 prefix_length = pos ? static_cast<size_t>(pos - name) : 0;
6516 }
6517
6518 bool operator()(const xml_attribute& a) const
6519 {
6520 const char_t* name = a.name();
6521
6522 if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false;
6523
6524 return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0;
6525 }
6526 };
6527
6528 PUGI__FN const char_t* namespace_uri(const xml_node& node)
6529 {
6530 namespace_uri_predicate pred = node.name();
6531
6532 xml_node p = node;
6533
6534 while (p)
6535 {
6536 xml_attribute a = p.find_attribute(pred);
6537
6538 if (a) return a.value();
6539
6540 p = p.parent();
6541 }
6542
6543 return PUGIXML_TEXT("");
6544 }
6545
6546 PUGI__FN const char_t* namespace_uri(const xml_attribute& attr, const xml_node& parent)
6547 {
6548 namespace_uri_predicate pred = attr.name();
6549
6550 // Default namespace does not apply to attributes
6551 if (!pred.prefix) return PUGIXML_TEXT("");
6552
6553 xml_node p = parent;
6554
6555 while (p)
6556 {
6557 xml_attribute a = p.find_attribute(pred);
6558
6559 if (a) return a.value();
6560
6561 p = p.parent();
6562 }
6563
6564 return PUGIXML_TEXT("");
6565 }
6566
6567 PUGI__FN const char_t* namespace_uri(const xpath_node& node)
6568 {
6569 return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
6570 }
6571
6572 PUGI__FN void normalize_space(char_t* buffer)
6573 {
6574 char_t* write = buffer;
6575
6576 for (char_t* it = buffer; *it; )
6577 {
6578 char_t ch = *it++;
6579
6580 if (PUGI__IS_CHARTYPE(ch, ct_space))
6581 {
6582 // replace whitespace sequence with single space
6583 while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
6584
6585 // avoid leading spaces
6586 if (write != buffer) *write++ = ' ';
6587 }
6588 else *write++ = ch;
6589 }
6590
6591 // remove trailing space
6592 if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
6593
6594 // zero-terminate
6595 *write = 0;
6596 }
6597
6598 PUGI__FN void translate(char_t* buffer, const char_t* from, const char_t* to)
6599 {
6600 size_t to_length = strlength(to);
6601
6602 char_t* write = buffer;
6603
6604 while (*buffer)
6605 {
6606 PUGI__DMC_VOLATILE char_t ch = *buffer++;
6607
6608 const char_t* pos = find_char(from, ch);
6609
6610 if (!pos)
6611 *write++ = ch; // do not process
6612 else if (static_cast<size_t>(pos - from) < to_length)
6613 *write++ = to[pos - from]; // replace
6614 }
6615
6616 // zero-terminate
6617 *write = 0;
6618 }
6619
6620 struct xpath_variable_boolean: xpath_variable
6621 {
6622 xpath_variable_boolean(): value(false)
6623 {
6624 }
6625
6626 bool value;
6627 char_t name[1];
6628 };
6629
6630 struct xpath_variable_number: xpath_variable
6631 {
6632 xpath_variable_number(): value(0)
6633 {
6634 }
6635
6636 double value;
6637 char_t name[1];
6638 };
6639
6640 struct xpath_variable_string: xpath_variable
6641 {
6642 xpath_variable_string(): value(0)
6643 {
6644 }
6645
6646 ~xpath_variable_string()
6647 {
6648 if (value) xml_memory::deallocate(value);
6649 }
6650
6651 char_t* value;
6652 char_t name[1];
6653 };
6654
6655 struct xpath_variable_node_set: xpath_variable
6656 {
6657 xpath_node_set value;
6658 char_t name[1];
6659 };
6660
6661 static const xpath_node_set dummy_node_set;
6662
6663 PUGI__FN unsigned int hash_string(const char_t* str)
6664 {
6665 // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
6666 unsigned int result = 0;
6667
6668 while (*str)
6669 {
6670 result += static_cast<unsigned int>(*str++);
6671 result += result << 10;
6672 result ^= result >> 6;
6673 }
6674
6675 result += result << 3;
6676 result ^= result >> 11;
6677 result += result << 15;
6678
6679 return result;
6680 }
6681
6682 template <typename T> PUGI__FN T* new_xpath_variable(const char_t* name)
6683 {
6684 size_t length = strlength(name);
6685 if (length == 0) return 0; // empty variable names are invalid
6686
6687 // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters
6688 void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t));
6689 if (!memory) return 0;
6690
6691 T* result = new (memory) T();
6692
6693 memcpy(result->name, name, (length + 1) * sizeof(char_t));
6694
6695 return result;
6696 }
6697
6698 PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)
6699 {
6700 switch (type)
6701 {
6702 case xpath_type_node_set:
6703 return new_xpath_variable<xpath_variable_node_set>(name);
6704
6705 case xpath_type_number:
6706 return new_xpath_variable<xpath_variable_number>(name);
6707
6708 case xpath_type_string:
6709 return new_xpath_variable<xpath_variable_string>(name);
6710
6711 case xpath_type_boolean:
6712 return new_xpath_variable<xpath_variable_boolean>(name);
6713
6714 default:
6715 return 0;
6716 }
6717 }
6718
6719 template <typename T> PUGI__FN void delete_xpath_variable(T* var)
6720 {
6721 var->~T();
6722 xml_memory::deallocate(var);
6723 }
6724
6725 PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
6726 {
6727 switch (type)
6728 {
6729 case xpath_type_node_set:
6730 delete_xpath_variable(static_cast<xpath_variable_node_set*>(var));
6731 break;
6732
6733 case xpath_type_number:
6734 delete_xpath_variable(static_cast<xpath_variable_number*>(var));
6735 break;
6736
6737 case xpath_type_string:
6738 delete_xpath_variable(static_cast<xpath_variable_string*>(var));
6739 break;
6740
6741 case xpath_type_boolean:
6742 delete_xpath_variable(static_cast<xpath_variable_boolean*>(var));
6743 break;
6744
6745 default:
6746 assert(!"Invalid variable type");
6747 }
6748 }
6749
6750 PUGI__FN xpath_variable* get_variable(xpath_variable_set* set, const char_t* begin, const char_t* end)
6751 {
6752 char_t buffer[32];
6753
6754 size_t length = static_cast<size_t>(end - begin);
6755 char_t* scratch = buffer;
6756
6757 if (length >= sizeof(buffer) / sizeof(buffer[0]))
6758 {
6759 // need to make dummy on-heap copy
6760 scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
6761 if (!scratch) return 0;
6762 }
6763
6764 // copy string to zero-terminated buffer and perform lookup
6765 memcpy(scratch, begin, length * sizeof(char_t));
6766 scratch[length] = 0;
6767
6768 xpath_variable* result = set->get(scratch);
6769
6770 // free dummy buffer
6771 if (scratch != buffer) xml_memory::deallocate(scratch);
6772
6773 return result;
6774 }
6775PUGI__NS_END
6776
6777// Internal node set class
6778PUGI__NS_BEGIN
6779 PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev)
6780 {
6781 xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
6782
6783 if (type == xpath_node_set::type_unsorted)
6784 {
6785 sort(begin, end, document_order_comparator());
6786
6787 type = xpath_node_set::type_sorted;
6788 }
6789
6790 if (type != order) reverse(begin, end);
6791
6792 return order;
6793 }
6794
6795 PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)
6796 {
6797 if (begin == end) return xpath_node();
6798
6799 switch (type)
6800 {
6801 case xpath_node_set::type_sorted:
6802 return *begin;
6803
6804 case xpath_node_set::type_sorted_reverse:
6805 return *(end - 1);
6806
6807 case xpath_node_set::type_unsorted:
6808 return *min_element(begin, end, document_order_comparator());
6809
6810 default:
6811 assert(!"Invalid node set type");
6812 return xpath_node();
6813 }
6814 }
6815
6816 class xpath_node_set_raw
6817 {
6818 xpath_node_set::type_t _type;
6819
6820 xpath_node* _begin;
6821 xpath_node* _end;
6822 xpath_node* _eos;
6823
6824 public:
6825 xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0)
6826 {
6827 }
6828
6829 xpath_node* begin() const
6830 {
6831 return _begin;
6832 }
6833
6834 xpath_node* end() const
6835 {
6836 return _end;
6837 }
6838
6839 bool empty() const
6840 {
6841 return _begin == _end;
6842 }
6843
6844 size_t size() const
6845 {
6846 return static_cast<size_t>(_end - _begin);
6847 }
6848
6849 xpath_node first() const
6850 {
6851 return xpath_first(_begin, _end, _type);
6852 }
6853
6854 void push_back(const xpath_node& node, xpath_allocator* alloc)
6855 {
6856 if (_end == _eos)
6857 {
6858 size_t capacity = static_cast<size_t>(_eos - _begin);
6859
6860 // get new capacity (1.5x rule)
6861 size_t new_capacity = capacity + capacity / 2 + 1;
6862
6863 // reallocate the old array or allocate a new one
6864 xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
6865 assert(data);
6866
6867 // finalize
6868 _begin = data;
6869 _end = data + capacity;
6870 _eos = data + new_capacity;
6871 }
6872
6873 *_end++ = node;
6874 }
6875
6876 void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc)
6877 {
6878 size_t size_ = static_cast<size_t>(_end - _begin);
6879 size_t capacity = static_cast<size_t>(_eos - _begin);
6880 size_t count = static_cast<size_t>(end_ - begin_);
6881
6882 if (size_ + count > capacity)
6883 {
6884 // reallocate the old array or allocate a new one
6885 xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node)));
6886 assert(data);
6887
6888 // finalize
6889 _begin = data;
6890 _end = data + size_;
6891 _eos = data + size_ + count;
6892 }
6893
6894 memcpy(_end, begin_, count * sizeof(xpath_node));
6895 _end += count;
6896 }
6897
6898 void sort_do()
6899 {
6900 _type = xpath_sort(_begin, _end, _type, false);
6901 }
6902
6903 void truncate(xpath_node* pos)
6904 {
6905 assert(_begin <= pos && pos <= _end);
6906
6907 _end = pos;
6908 }
6909
6910 void remove_duplicates()
6911 {
6912 if (_type == xpath_node_set::type_unsorted)
6913 sort(_begin, _end, duplicate_comparator());
6914
6915 _end = unique(_begin, _end);
6916 }
6917
6918 xpath_node_set::type_t type() const
6919 {
6920 return _type;
6921 }
6922
6923 void set_type(xpath_node_set::type_t value)
6924 {
6925 _type = value;
6926 }
6927 };
6928PUGI__NS_END
6929
6930PUGI__NS_BEGIN
6931 struct xpath_context
6932 {
6933 xpath_node n;
6934 size_t position, size;
6935
6936 xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_)
6937 {
6938 }
6939 };
6940
6941 enum lexeme_t
6942 {
6943 lex_none = 0,
6944 lex_equal,
6945 lex_not_equal,
6946 lex_less,
6947 lex_greater,
6948 lex_less_or_equal,
6949 lex_greater_or_equal,
6950 lex_plus,
6951 lex_minus,
6952 lex_multiply,
6953 lex_union,
6954 lex_var_ref,
6955 lex_open_brace,
6956 lex_close_brace,
6957 lex_quoted_string,
6958 lex_number,
6959 lex_slash,
6960 lex_double_slash,
6961 lex_open_square_brace,
6962 lex_close_square_brace,
6963 lex_string,
6964 lex_comma,
6965 lex_axis_attribute,
6966 lex_dot,
6967 lex_double_dot,
6968 lex_double_colon,
6969 lex_eof
6970 };
6971
6972 struct xpath_lexer_string
6973 {
6974 const char_t* begin;
6975 const char_t* end;
6976
6977 xpath_lexer_string(): begin(0), end(0)
6978 {
6979 }
6980
6981 bool operator==(const char_t* other) const
6982 {
6983 size_t length = static_cast<size_t>(end - begin);
6984
6985 return strequalrange(other, begin, length);
6986 }
6987 };
6988
6989 class xpath_lexer
6990 {
6991 const char_t* _cur;
6992 const char_t* _cur_lexeme_pos;
6993 xpath_lexer_string _cur_lexeme_contents;
6994
6995 lexeme_t _cur_lexeme;
6996
6997 public:
6998 explicit xpath_lexer(const char_t* query): _cur(query)
6999 {
7000 next();
7001 }
7002
7003 const char_t* state() const
7004 {
7005 return _cur;
7006 }
7007
7008 void next()
7009 {
7010 const char_t* cur = _cur;
7011
7012 while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
7013
7014 // save lexeme position for error reporting
7015 _cur_lexeme_pos = cur;
7016
7017 switch (*cur)
7018 {
7019 case 0:
7020 _cur_lexeme = lex_eof;
7021 break;
7022
7023 case '>':
7024 if (*(cur+1) == '=')
7025 {
7026 cur += 2;
7027 _cur_lexeme = lex_greater_or_equal;
7028 }
7029 else
7030 {
7031 cur += 1;
7032 _cur_lexeme = lex_greater;
7033 }
7034 break;
7035
7036 case '<':
7037 if (*(cur+1) == '=')
7038 {
7039 cur += 2;
7040 _cur_lexeme = lex_less_or_equal;
7041 }
7042 else
7043 {
7044 cur += 1;
7045 _cur_lexeme = lex_less;
7046 }
7047 break;
7048
7049 case '!':
7050 if (*(cur+1) == '=')
7051 {
7052 cur += 2;
7053 _cur_lexeme = lex_not_equal;
7054 }
7055 else
7056 {
7057 _cur_lexeme = lex_none;
7058 }
7059 break;
7060
7061 case '=':
7062 cur += 1;
7063 _cur_lexeme = lex_equal;
7064
7065 break;
7066
7067 case '+':
7068 cur += 1;
7069 _cur_lexeme = lex_plus;
7070
7071 break;
7072
7073 case '-':
7074 cur += 1;
7075 _cur_lexeme = lex_minus;
7076
7077 break;
7078
7079 case '*':
7080 cur += 1;
7081 _cur_lexeme = lex_multiply;
7082
7083 break;
7084
7085 case '|':
7086 cur += 1;
7087 _cur_lexeme = lex_union;
7088
7089 break;
7090
7091 case '$':
7092 cur += 1;
7093
7094 if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
7095 {
7096 _cur_lexeme_contents.begin = cur;
7097
7098 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
7099
7100 if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname
7101 {
7102 cur++; // :
7103
7104 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
7105 }
7106
7107 _cur_lexeme_contents.end = cur;
7108
7109 _cur_lexeme = lex_var_ref;
7110 }
7111 else
7112 {
7113 _cur_lexeme = lex_none;
7114 }
7115
7116 break;
7117
7118 case '(':
7119 cur += 1;
7120 _cur_lexeme = lex_open_brace;
7121
7122 break;
7123
7124 case ')':
7125 cur += 1;
7126 _cur_lexeme = lex_close_brace;
7127
7128 break;
7129
7130 case '[':
7131 cur += 1;
7132 _cur_lexeme = lex_open_square_brace;
7133
7134 break;
7135
7136 case ']':
7137 cur += 1;
7138 _cur_lexeme = lex_close_square_brace;
7139
7140 break;
7141
7142 case ',':
7143 cur += 1;
7144 _cur_lexeme = lex_comma;
7145
7146 break;
7147
7148 case '/':
7149 if (*(cur+1) == '/')
7150 {
7151 cur += 2;
7152 _cur_lexeme = lex_double_slash;
7153 }
7154 else
7155 {
7156 cur += 1;
7157 _cur_lexeme = lex_slash;
7158 }
7159 break;
7160
7161 case '.':
7162 if (*(cur+1) == '.')
7163 {
7164 cur += 2;
7165 _cur_lexeme = lex_double_dot;
7166 }
7167 else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
7168 {
7169 _cur_lexeme_contents.begin = cur; // .
7170
7171 ++cur;
7172
7173 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
7174
7175 _cur_lexeme_contents.end = cur;
7176
7177 _cur_lexeme = lex_number;
7178 }
7179 else
7180 {
7181 cur += 1;
7182 _cur_lexeme = lex_dot;
7183 }
7184 break;
7185
7186 case '@':
7187 cur += 1;
7188 _cur_lexeme = lex_axis_attribute;
7189
7190 break;
7191
7192 case '"':
7193 case '\'':
7194 {
7195 char_t terminator = *cur;
7196
7197 ++cur;
7198
7199 _cur_lexeme_contents.begin = cur;
7200 while (*cur && *cur != terminator) cur++;
7201 _cur_lexeme_contents.end = cur;
7202
7203 if (!*cur)
7204 _cur_lexeme = lex_none;
7205 else
7206 {
7207 cur += 1;
7208 _cur_lexeme = lex_quoted_string;
7209 }
7210
7211 break;
7212 }
7213
7214 case ':':
7215 if (*(cur+1) == ':')
7216 {
7217 cur += 2;
7218 _cur_lexeme = lex_double_colon;
7219 }
7220 else
7221 {
7222 _cur_lexeme = lex_none;
7223 }
7224 break;
7225
7226 default:
7227 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
7228 {
7229 _cur_lexeme_contents.begin = cur;
7230
7231 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
7232
7233 if (*cur == '.')
7234 {
7235 cur++;
7236
7237 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
7238 }
7239
7240 _cur_lexeme_contents.end = cur;
7241
7242 _cur_lexeme = lex_number;
7243 }
7244 else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
7245 {
7246 _cur_lexeme_contents.begin = cur;
7247
7248 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
7249
7250 if (cur[0] == ':')
7251 {
7252 if (cur[1] == '*') // namespace test ncname:*
7253 {
7254 cur += 2; // :*
7255 }
7256 else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
7257 {
7258 cur++; // :
7259
7260 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
7261 }
7262 }
7263
7264 _cur_lexeme_contents.end = cur;
7265
7266 _cur_lexeme = lex_string;
7267 }
7268 else
7269 {
7270 _cur_lexeme = lex_none;
7271 }
7272 }
7273
7274 _cur = cur;
7275 }
7276
7277 lexeme_t current() const
7278 {
7279 return _cur_lexeme;
7280 }
7281
7282 const char_t* current_pos() const
7283 {
7284 return _cur_lexeme_pos;
7285 }
7286
7287 const xpath_lexer_string& contents() const
7288 {
7289 assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string);
7290
7291 return _cur_lexeme_contents;
7292 }
7293 };
7294
7295 enum ast_type_t
7296 {
7297 ast_op_or, // left or right
7298 ast_op_and, // left and right
7299 ast_op_equal, // left = right
7300 ast_op_not_equal, // left != right
7301 ast_op_less, // left < right
7302 ast_op_greater, // left > right
7303 ast_op_less_or_equal, // left <= right
7304 ast_op_greater_or_equal, // left >= right
7305 ast_op_add, // left + right
7306 ast_op_subtract, // left - right
7307 ast_op_multiply, // left * right
7308 ast_op_divide, // left / right
7309 ast_op_mod, // left % right
7310 ast_op_negate, // left - right
7311 ast_op_union, // left | right
7312 ast_predicate, // apply predicate to set; next points to next predicate
7313 ast_filter, // select * from left where right
7314 ast_filter_posinv, // select * from left where right; proximity position invariant
7315 ast_string_constant, // string constant
7316 ast_number_constant, // number constant
7317 ast_variable, // variable
7318 ast_func_last, // last()
7319 ast_func_position, // position()
7320 ast_func_count, // count(left)
7321 ast_func_id, // id(left)
7322 ast_func_local_name_0, // local-name()
7323 ast_func_local_name_1, // local-name(left)
7324 ast_func_namespace_uri_0, // namespace-uri()
7325 ast_func_namespace_uri_1, // namespace-uri(left)
7326 ast_func_name_0, // name()
7327 ast_func_name_1, // name(left)
7328 ast_func_string_0, // string()
7329 ast_func_string_1, // string(left)
7330 ast_func_concat, // concat(left, right, siblings)
7331 ast_func_starts_with, // starts_with(left, right)
7332 ast_func_contains, // contains(left, right)
7333 ast_func_substring_before, // substring-before(left, right)
7334 ast_func_substring_after, // substring-after(left, right)
7335 ast_func_substring_2, // substring(left, right)
7336 ast_func_substring_3, // substring(left, right, third)
7337 ast_func_string_length_0, // string-length()
7338 ast_func_string_length_1, // string-length(left)
7339 ast_func_normalize_space_0, // normalize-space()
7340 ast_func_normalize_space_1, // normalize-space(left)
7341 ast_func_translate, // translate(left, right, third)
7342 ast_func_boolean, // boolean(left)
7343 ast_func_not, // not(left)
7344 ast_func_true, // true()
7345 ast_func_false, // false()
7346 ast_func_lang, // lang(left)
7347 ast_func_number_0, // number()
7348 ast_func_number_1, // number(left)
7349 ast_func_sum, // sum(left)
7350 ast_func_floor, // floor(left)
7351 ast_func_ceiling, // ceiling(left)
7352 ast_func_round, // round(left)
7353 ast_step, // process set left with step
7354 ast_step_root // select root node
7355 };
7356
7357 enum axis_t
7358 {
7359 axis_ancestor,
7360 axis_ancestor_or_self,
7361 axis_attribute,
7362 axis_child,
7363 axis_descendant,
7364 axis_descendant_or_self,
7365 axis_following,
7366 axis_following_sibling,
7367 axis_namespace,
7368 axis_parent,
7369 axis_preceding,
7370 axis_preceding_sibling,
7371 axis_self
7372 };
7373
7374 enum nodetest_t
7375 {
7376 nodetest_none,
7377 nodetest_name,
7378 nodetest_type_node,
7379 nodetest_type_comment,
7380 nodetest_type_pi,
7381 nodetest_type_text,
7382 nodetest_pi,
7383 nodetest_all,
7384 nodetest_all_in_namespace
7385 };
7386
7387 template <axis_t N> struct axis_to_type
7388 {
7389 static const axis_t axis;
7390 };
7391
7392 template <axis_t N> const axis_t axis_to_type<N>::axis = N;
7393
7394 class xpath_ast_node
7395 {
7396 private:
7397 // node type
7398 char _type;
7399 char _rettype;
7400
7401 // for ast_step / ast_predicate
7402 char _axis;
7403 char _test;
7404
7405 // tree node structure
7406 xpath_ast_node* _left;
7407 xpath_ast_node* _right;
7408 xpath_ast_node* _next;
7409
7410 union
7411 {
7412 // value for ast_string_constant
7413 const char_t* string;
7414 // value for ast_number_constant
7415 double number;
7416 // variable for ast_variable
7417 xpath_variable* variable;
7418 // node test for ast_step (node name/namespace/node type/pi target)
7419 const char_t* nodetest;
7420 } _data;
7421
7422 xpath_ast_node(const xpath_ast_node&);
7423 xpath_ast_node& operator=(const xpath_ast_node&);
7424
7425 template <class Comp> static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)
7426 {
7427 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
7428
7429 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
7430 {
7431 if (lt == xpath_type_boolean || rt == xpath_type_boolean)
7432 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
7433 else if (lt == xpath_type_number || rt == xpath_type_number)
7434 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
7435 else if (lt == xpath_type_string || rt == xpath_type_string)
7436 {
7437 xpath_allocator_capture cr(stack.result);
7438
7439 xpath_string ls = lhs->eval_string(c, stack);
7440 xpath_string rs = rhs->eval_string(c, stack);
7441
7442 return comp(ls, rs);
7443 }
7444 }
7445 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
7446 {
7447 xpath_allocator_capture cr(stack.result);
7448
7449 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
7450 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7451
7452 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
7453 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7454 {
7455 xpath_allocator_capture cri(stack.result);
7456
7457 if (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))
7458 return true;
7459 }
7460
7461 return false;
7462 }
7463 else
7464 {
7465 if (lt == xpath_type_node_set)
7466 {
7467 swap(lhs, rhs);
7468 swap(lt, rt);
7469 }
7470
7471 if (lt == xpath_type_boolean)
7472 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
7473 else if (lt == xpath_type_number)
7474 {
7475 xpath_allocator_capture cr(stack.result);
7476
7477 double l = lhs->eval_number(c, stack);
7478 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7479
7480 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7481 {
7482 xpath_allocator_capture cri(stack.result);
7483
7484 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
7485 return true;
7486 }
7487
7488 return false;
7489 }
7490 else if (lt == xpath_type_string)
7491 {
7492 xpath_allocator_capture cr(stack.result);
7493
7494 xpath_string l = lhs->eval_string(c, stack);
7495 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7496
7497 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7498 {
7499 xpath_allocator_capture cri(stack.result);
7500
7501 if (comp(l, string_value(*ri, stack.result)))
7502 return true;
7503 }
7504
7505 return false;
7506 }
7507 }
7508
7509 assert(!"Wrong types");
7510 return false;
7511 }
7512
7513 template <class Comp> static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)
7514 {
7515 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
7516
7517 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
7518 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
7519 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
7520 {
7521 xpath_allocator_capture cr(stack.result);
7522
7523 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
7524 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7525
7526 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
7527 {
7528 xpath_allocator_capture cri(stack.result);
7529
7530 double l = convert_string_to_number(string_value(*li, stack.result).c_str());
7531
7532 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7533 {
7534 xpath_allocator_capture crii(stack.result);
7535
7536 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
7537 return true;
7538 }
7539 }
7540
7541 return false;
7542 }
7543 else if (lt != xpath_type_node_set && rt == xpath_type_node_set)
7544 {
7545 xpath_allocator_capture cr(stack.result);
7546
7547 double l = lhs->eval_number(c, stack);
7548 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7549
7550 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7551 {
7552 xpath_allocator_capture cri(stack.result);
7553
7554 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
7555 return true;
7556 }
7557
7558 return false;
7559 }
7560 else if (lt == xpath_type_node_set && rt != xpath_type_node_set)
7561 {
7562 xpath_allocator_capture cr(stack.result);
7563
7564 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
7565 double r = rhs->eval_number(c, stack);
7566
7567 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
7568 {
7569 xpath_allocator_capture cri(stack.result);
7570
7571 if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))
7572 return true;
7573 }
7574
7575 return false;
7576 }
7577 else
7578 {
7579 assert(!"Wrong types");
7580 return false;
7581 }
7582 }
7583
7584 void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack)
7585 {
7586 assert(ns.size() >= first);
7587
7588 size_t i = 1;
7589 size_t size = ns.size() - first;
7590
7591 xpath_node* last = ns.begin() + first;
7592
7593 // remove_if... or well, sort of
7594 for (xpath_node* it = last; it != ns.end(); ++it, ++i)
7595 {
7596 xpath_context c(*it, i, size);
7597
7598 if (expr->rettype() == xpath_type_number)
7599 {
7600 if (expr->eval_number(c, stack) == i)
7601 *last++ = *it;
7602 }
7603 else if (expr->eval_boolean(c, stack))
7604 *last++ = *it;
7605 }
7606
7607 ns.truncate(last);
7608 }
7609
7610 void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack)
7611 {
7612 if (ns.size() == first) return;
7613
7614 for (xpath_ast_node* pred = _right; pred; pred = pred->_next)
7615 {
7616 apply_predicate(ns, first, pred->_left, stack);
7617 }
7618 }
7619
7620 void step_push(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& parent, xpath_allocator* alloc)
7621 {
7622 if (!a) return;
7623
7624 const char_t* name = a.name();
7625
7626 // There are no attribute nodes corresponding to attributes that declare namespaces
7627 // That is, "xmlns:..." or "xmlns"
7628 if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')) return;
7629
7630 switch (_test)
7631 {
7632 case nodetest_name:
7633 if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc);
7634 break;
7635
7636 case nodetest_type_node:
7637 case nodetest_all:
7638 ns.push_back(xpath_node(a, parent), alloc);
7639 break;
7640
7641 case nodetest_all_in_namespace:
7642 if (starts_with(name, _data.nodetest))
7643 ns.push_back(xpath_node(a, parent), alloc);
7644 break;
7645
7646 default:
7647 ;
7648 }
7649 }
7650
7651 void step_push(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc)
7652 {
7653 if (!n) return;
7654
7655 switch (_test)
7656 {
7657 case nodetest_name:
7658 if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc);
7659 break;
7660
7661 case nodetest_type_node:
7662 ns.push_back(n, alloc);
7663 break;
7664
7665 case nodetest_type_comment:
7666 if (n.type() == node_comment)
7667 ns.push_back(n, alloc);
7668 break;
7669
7670 case nodetest_type_text:
7671 if (n.type() == node_pcdata || n.type() == node_cdata)
7672 ns.push_back(n, alloc);
7673 break;
7674
7675 case nodetest_type_pi:
7676 if (n.type() == node_pi)
7677 ns.push_back(n, alloc);
7678 break;
7679
7680 case nodetest_pi:
7681 if (n.type() == node_pi && strequal(n.name(), _data.nodetest))
7682 ns.push_back(n, alloc);
7683 break;
7684
7685 case nodetest_all:
7686 if (n.type() == node_element)
7687 ns.push_back(n, alloc);
7688 break;
7689
7690 case nodetest_all_in_namespace:
7691 if (n.type() == node_element && starts_with(n.name(), _data.nodetest))
7692 ns.push_back(n, alloc);
7693 break;
7694
7695 default:
7696 assert(!"Unknown axis");
7697 }
7698 }
7699
7700 template <class T> void step_fill(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc, T)
7701 {
7702 const axis_t axis = T::axis;
7703
7704 switch (axis)
7705 {
7706 case axis_attribute:
7707 {
7708 for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute())
7709 step_push(ns, a, n, alloc);
7710
7711 break;
7712 }
7713
7714 case axis_child:
7715 {
7716 for (xml_node c = n.first_child(); c; c = c.next_sibling())
7717 step_push(ns, c, alloc);
7718
7719 break;
7720 }
7721
7722 case axis_descendant:
7723 case axis_descendant_or_self:
7724 {
7725 if (axis == axis_descendant_or_self)
7726 step_push(ns, n, alloc);
7727
7728 xml_node cur = n.first_child();
7729
7730 while (cur && cur != n)
7731 {
7732 step_push(ns, cur, alloc);
7733
7734 if (cur.first_child())
7735 cur = cur.first_child();
7736 else if (cur.next_sibling())
7737 cur = cur.next_sibling();
7738 else
7739 {
7740 while (!cur.next_sibling() && cur != n)
7741 cur = cur.parent();
7742
7743 if (cur != n) cur = cur.next_sibling();
7744 }
7745 }
7746
7747 break;
7748 }
7749
7750 case axis_following_sibling:
7751 {
7752 for (xml_node c = n.next_sibling(); c; c = c.next_sibling())
7753 step_push(ns, c, alloc);
7754
7755 break;
7756 }
7757
7758 case axis_preceding_sibling:
7759 {
7760 for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling())
7761 step_push(ns, c, alloc);
7762
7763 break;
7764 }
7765
7766 case axis_following:
7767 {
7768 xml_node cur = n;
7769
7770 // exit from this node so that we don't include descendants
7771 while (cur && !cur.next_sibling()) cur = cur.parent();
7772 cur = cur.next_sibling();
7773
7774 for (;;)
7775 {
7776 step_push(ns, cur, alloc);
7777
7778 if (cur.first_child())
7779 cur = cur.first_child();
7780 else if (cur.next_sibling())
7781 cur = cur.next_sibling();
7782 else
7783 {
7784 while (cur && !cur.next_sibling()) cur = cur.parent();
7785 cur = cur.next_sibling();
7786
7787 if (!cur) break;
7788 }
7789 }
7790
7791 break;
7792 }
7793
7794 case axis_preceding:
7795 {
7796 xml_node cur = n;
7797
7798 while (cur && !cur.previous_sibling()) cur = cur.parent();
7799 cur = cur.previous_sibling();
7800
7801 for (;;)
7802 {
7803 if (cur.last_child())
7804 cur = cur.last_child();
7805 else
7806 {
7807 // leaf node, can't be ancestor
7808 step_push(ns, cur, alloc);
7809
7810 if (cur.previous_sibling())
7811 cur = cur.previous_sibling();
7812 else
7813 {
7814 do
7815 {
7816 cur = cur.parent();
7817 if (!cur) break;
7818
7819 if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc);
7820 }
7821 while (!cur.previous_sibling());
7822
7823 cur = cur.previous_sibling();
7824
7825 if (!cur) break;
7826 }
7827 }
7828 }
7829
7830 break;
7831 }
7832
7833 case axis_ancestor:
7834 case axis_ancestor_or_self:
7835 {
7836 if (axis == axis_ancestor_or_self)
7837 step_push(ns, n, alloc);
7838
7839 xml_node cur = n.parent();
7840
7841 while (cur)
7842 {
7843 step_push(ns, cur, alloc);
7844
7845 cur = cur.parent();
7846 }
7847
7848 break;
7849 }
7850
7851 case axis_self:
7852 {
7853 step_push(ns, n, alloc);
7854
7855 break;
7856 }
7857
7858 case axis_parent:
7859 {
7860 if (n.parent()) step_push(ns, n.parent(), alloc);
7861
7862 break;
7863 }
7864
7865 default:
7866 assert(!"Unimplemented axis");
7867 }
7868 }
7869
7870 template <class T> void step_fill(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& p, xpath_allocator* alloc, T v)
7871 {
7872 const axis_t axis = T::axis;
7873
7874 switch (axis)
7875 {
7876 case axis_ancestor:
7877 case axis_ancestor_or_self:
7878 {
7879 if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test
7880 step_push(ns, a, p, alloc);
7881
7882 xml_node cur = p;
7883
7884 while (cur)
7885 {
7886 step_push(ns, cur, alloc);
7887
7888 cur = cur.parent();
7889 }
7890
7891 break;
7892 }
7893
7894 case axis_descendant_or_self:
7895 case axis_self:
7896 {
7897 if (_test == nodetest_type_node) // reject attributes based on principal node type test
7898 step_push(ns, a, p, alloc);
7899
7900 break;
7901 }
7902
7903 case axis_following:
7904 {
7905 xml_node cur = p;
7906
7907 for (;;)
7908 {
7909 if (cur.first_child())
7910 cur = cur.first_child();
7911 else if (cur.next_sibling())
7912 cur = cur.next_sibling();
7913 else
7914 {
7915 while (cur && !cur.next_sibling()) cur = cur.parent();
7916 cur = cur.next_sibling();
7917
7918 if (!cur) break;
7919 }
7920
7921 step_push(ns, cur, alloc);
7922 }
7923
7924 break;
7925 }
7926
7927 case axis_parent:
7928 {
7929 step_push(ns, p, alloc);
7930
7931 break;
7932 }
7933
7934 case axis_preceding:
7935 {
7936 // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding
7937 step_fill(ns, p, alloc, v);
7938 break;
7939 }
7940
7941 default:
7942 assert(!"Unimplemented axis");
7943 }
7944 }
7945
7946 template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, T v)
7947 {
7948 const axis_t axis = T::axis;
7949 bool attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
7950
7951 xpath_node_set_raw ns;
7952 ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted);
7953
7954 if (_left)
7955 {
7956 xpath_node_set_raw s = _left->eval_node_set(c, stack);
7957
7958 // self axis preserves the original order
7959 if (axis == axis_self) ns.set_type(s.type());
7960
7961 for (const xpath_node* it = s.begin(); it != s.end(); ++it)
7962 {
7963 size_t size = ns.size();
7964
7965 // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes
7966 if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);
7967
7968 if (it->node())
7969 step_fill(ns, it->node(), stack.result, v);
7970 else if (attributes)
7971 step_fill(ns, it->attribute(), it->parent(), stack.result, v);
7972
7973 apply_predicates(ns, size, stack);
7974 }
7975 }
7976 else
7977 {
7978 if (c.n.node())
7979 step_fill(ns, c.n.node(), stack.result, v);
7980 else if (attributes)
7981 step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v);
7982
7983 apply_predicates(ns, 0, stack);
7984 }
7985
7986 // child, attribute and self axes always generate unique set of nodes
7987 // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice
7988 if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted)
7989 ns.remove_duplicates();
7990
7991 return ns;
7992 }
7993
7994 public:
7995 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value):
7996 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
7997 {
7998 assert(type == ast_string_constant);
7999 _data.string = value;
8000 }
8001
8002 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value):
8003 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
8004 {
8005 assert(type == ast_number_constant);
8006 _data.number = value;
8007 }
8008
8009 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value):
8010 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
8011 {
8012 assert(type == ast_variable);
8013 _data.variable = value;
8014 }
8015
8016 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0):
8017 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
8018 {
8019 }
8020
8021 xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents):
8022 _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(static_cast<char>(axis)), _test(static_cast<char>(test)), _left(left), _right(0), _next(0)
8023 {
8024 _data.nodetest = contents;
8025 }
8026
8027 void set_next(xpath_ast_node* value)
8028 {
8029 _next = value;
8030 }
8031
8032 void set_right(xpath_ast_node* value)
8033 {
8034 _right = value;
8035 }
8036
8037 bool eval_boolean(const xpath_context& c, const xpath_stack& stack)
8038 {
8039 switch (_type)
8040 {
8041 case ast_op_or:
8042 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
8043
8044 case ast_op_and:
8045 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
8046
8047 case ast_op_equal:
8048 return compare_eq(_left, _right, c, stack, equal_to());
8049
8050 case ast_op_not_equal:
8051 return compare_eq(_left, _right, c, stack, not_equal_to());
8052
8053 case ast_op_less:
8054 return compare_rel(_left, _right, c, stack, less());
8055
8056 case ast_op_greater:
8057 return compare_rel(_right, _left, c, stack, less());
8058
8059 case ast_op_less_or_equal:
8060 return compare_rel(_left, _right, c, stack, less_equal());
8061
8062 case ast_op_greater_or_equal:
8063 return compare_rel(_right, _left, c, stack, less_equal());
8064
8065 case ast_func_starts_with:
8066 {
8067 xpath_allocator_capture cr(stack.result);
8068
8069 xpath_string lr = _left->eval_string(c, stack);
8070 xpath_string rr = _right->eval_string(c, stack);
8071
8072 return starts_with(lr.c_str(), rr.c_str());
8073 }
8074
8075 case ast_func_contains:
8076 {
8077 xpath_allocator_capture cr(stack.result);
8078
8079 xpath_string lr = _left->eval_string(c, stack);
8080 xpath_string rr = _right->eval_string(c, stack);
8081
8082 return find_substring(lr.c_str(), rr.c_str()) != 0;
8083 }
8084
8085 case ast_func_boolean:
8086 return _left->eval_boolean(c, stack);
8087
8088 case ast_func_not:
8089 return !_left->eval_boolean(c, stack);
8090
8091 case ast_func_true:
8092 return true;
8093
8094 case ast_func_false:
8095 return false;
8096
8097 case ast_func_lang:
8098 {
8099 if (c.n.attribute()) return false;
8100
8101 xpath_allocator_capture cr(stack.result);
8102
8103 xpath_string lang = _left->eval_string(c, stack);
8104
8105 for (xml_node n = c.n.node(); n; n = n.parent())
8106 {
8107 xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang"));
8108
8109 if (a)
8110 {
8111 const char_t* value = a.value();
8112
8113 // strnicmp / strncasecmp is not portable
8114 for (const char_t* lit = lang.c_str(); *lit; ++lit)
8115 {
8116 if (tolower_ascii(*lit) != tolower_ascii(*value)) return false;
8117 ++value;
8118 }
8119
8120 return *value == 0 || *value == '-';
8121 }
8122 }
8123
8124 return false;
8125 }
8126
8127 case ast_variable:
8128 {
8129 assert(_rettype == _data.variable->type());
8130
8131 if (_rettype == xpath_type_boolean)
8132 return _data.variable->get_boolean();
8133
8134 // fallthrough to type conversion
8135 }
8136
8137 default:
8138 {
8139 switch (_rettype)
8140 {
8141 case xpath_type_number:
8142 return convert_number_to_boolean(eval_number(c, stack));
8143
8144 case xpath_type_string:
8145 {
8146 xpath_allocator_capture cr(stack.result);
8147
8148 return !eval_string(c, stack).empty();
8149 }
8150
8151 case xpath_type_node_set:
8152 {
8153 xpath_allocator_capture cr(stack.result);
8154
8155 return !eval_node_set(c, stack).empty();
8156 }
8157
8158 default:
8159 assert(!"Wrong expression for return type boolean");
8160 return false;
8161 }
8162 }
8163 }
8164 }
8165
8166 double eval_number(const xpath_context& c, const xpath_stack& stack)
8167 {
8168 switch (_type)
8169 {
8170 case ast_op_add:
8171 return _left->eval_number(c, stack) + _right->eval_number(c, stack);
8172
8173 case ast_op_subtract:
8174 return _left->eval_number(c, stack) - _right->eval_number(c, stack);
8175
8176 case ast_op_multiply:
8177 return _left->eval_number(c, stack) * _right->eval_number(c, stack);
8178
8179 case ast_op_divide:
8180 return _left->eval_number(c, stack) / _right->eval_number(c, stack);
8181
8182 case ast_op_mod:
8183 return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
8184
8185 case ast_op_negate:
8186 return -_left->eval_number(c, stack);
8187
8188 case ast_number_constant:
8189 return _data.number;
8190
8191 case ast_func_last:
8192 return static_cast<double>(c.size);
8193
8194 case ast_func_position:
8195 return static_cast<double>(c.position);
8196
8197 case ast_func_count:
8198 {
8199 xpath_allocator_capture cr(stack.result);
8200
8201 return static_cast<double>(_left->eval_node_set(c, stack).size());
8202 }
8203
8204 case ast_func_string_length_0:
8205 {
8206 xpath_allocator_capture cr(stack.result);
8207
8208 return static_cast<double>(string_value(c.n, stack.result).length());
8209 }
8210
8211 case ast_func_string_length_1:
8212 {
8213 xpath_allocator_capture cr(stack.result);
8214
8215 return static_cast<double>(_left->eval_string(c, stack).length());
8216 }
8217
8218 case ast_func_number_0:
8219 {
8220 xpath_allocator_capture cr(stack.result);
8221
8222 return convert_string_to_number(string_value(c.n, stack.result).c_str());
8223 }
8224
8225 case ast_func_number_1:
8226 return _left->eval_number(c, stack);
8227
8228 case ast_func_sum:
8229 {
8230 xpath_allocator_capture cr(stack.result);
8231
8232 double r = 0;
8233
8234 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8235
8236 for (const xpath_node* it = ns.begin(); it != ns.end(); ++it)
8237 {
8238 xpath_allocator_capture cri(stack.result);
8239
8240 r += convert_string_to_number(string_value(*it, stack.result).c_str());
8241 }
8242
8243 return r;
8244 }
8245
8246 case ast_func_floor:
8247 {
8248 double r = _left->eval_number(c, stack);
8249
8250 return r == r ? floor(r) : r;
8251 }
8252
8253 case ast_func_ceiling:
8254 {
8255 double r = _left->eval_number(c, stack);
8256
8257 return r == r ? ceil(r) : r;
8258 }
8259
8260 case ast_func_round:
8261 return round_nearest_nzero(_left->eval_number(c, stack));
8262
8263 case ast_variable:
8264 {
8265 assert(_rettype == _data.variable->type());
8266
8267 if (_rettype == xpath_type_number)
8268 return _data.variable->get_number();
8269
8270 // fallthrough to type conversion
8271 }
8272
8273 default:
8274 {
8275 switch (_rettype)
8276 {
8277 case xpath_type_boolean:
8278 return eval_boolean(c, stack) ? 1 : 0;
8279
8280 case xpath_type_string:
8281 {
8282 xpath_allocator_capture cr(stack.result);
8283
8284 return convert_string_to_number(eval_string(c, stack).c_str());
8285 }
8286
8287 case xpath_type_node_set:
8288 {
8289 xpath_allocator_capture cr(stack.result);
8290
8291 return convert_string_to_number(eval_string(c, stack).c_str());
8292 }
8293
8294 default:
8295 assert(!"Wrong expression for return type number");
8296 return 0;
8297 }
8298
8299 }
8300 }
8301 }
8302
8303 xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack)
8304 {
8305 assert(_type == ast_func_concat);
8306
8307 xpath_allocator_capture ct(stack.temp);
8308
8309 // count the string number
8310 size_t count = 1;
8311 for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++;
8312
8313 // gather all strings
8314 xpath_string static_buffer[4];
8315 xpath_string* buffer = static_buffer;
8316
8317 // allocate on-heap for large concats
8318 if (count > sizeof(static_buffer) / sizeof(static_buffer[0]))
8319 {
8320 buffer = static_cast<xpath_string*>(stack.temp->allocate(count * sizeof(xpath_string)));
8321 assert(buffer);
8322 }
8323
8324 // evaluate all strings to temporary stack
8325 xpath_stack swapped_stack = {stack.temp, stack.result};
8326
8327 buffer[0] = _left->eval_string(c, swapped_stack);
8328
8329 size_t pos = 1;
8330 for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);
8331 assert(pos == count);
8332
8333 // get total length
8334 size_t length = 0;
8335 for (size_t i = 0; i < count; ++i) length += buffer[i].length();
8336
8337 // create final string
8338 char_t* result = static_cast<char_t*>(stack.result->allocate((length + 1) * sizeof(char_t)));
8339 assert(result);
8340
8341 char_t* ri = result;
8342
8343 for (size_t j = 0; j < count; ++j)
8344 for (const char_t* bi = buffer[j].c_str(); *bi; ++bi)
8345 *ri++ = *bi;
8346
8347 *ri = 0;
8348
8349 return xpath_string(result, true);
8350 }
8351
8352 xpath_string eval_string(const xpath_context& c, const xpath_stack& stack)
8353 {
8354 switch (_type)
8355 {
8356 case ast_string_constant:
8357 return xpath_string_const(_data.string);
8358
8359 case ast_func_local_name_0:
8360 {
8361 xpath_node na = c.n;
8362
8363 return xpath_string_const(local_name(na));
8364 }
8365
8366 case ast_func_local_name_1:
8367 {
8368 xpath_allocator_capture cr(stack.result);
8369
8370 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8371 xpath_node na = ns.first();
8372
8373 return xpath_string_const(local_name(na));
8374 }
8375
8376 case ast_func_name_0:
8377 {
8378 xpath_node na = c.n;
8379
8380 return xpath_string_const(qualified_name(na));
8381 }
8382
8383 case ast_func_name_1:
8384 {
8385 xpath_allocator_capture cr(stack.result);
8386
8387 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8388 xpath_node na = ns.first();
8389
8390 return xpath_string_const(qualified_name(na));
8391 }
8392
8393 case ast_func_namespace_uri_0:
8394 {
8395 xpath_node na = c.n;
8396
8397 return xpath_string_const(namespace_uri(na));
8398 }
8399
8400 case ast_func_namespace_uri_1:
8401 {
8402 xpath_allocator_capture cr(stack.result);
8403
8404 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8405 xpath_node na = ns.first();
8406
8407 return xpath_string_const(namespace_uri(na));
8408 }
8409
8410 case ast_func_string_0:
8411 return string_value(c.n, stack.result);
8412
8413 case ast_func_string_1:
8414 return _left->eval_string(c, stack);
8415
8416 case ast_func_concat:
8417 return eval_string_concat(c, stack);
8418
8419 case ast_func_substring_before:
8420 {
8421 xpath_allocator_capture cr(stack.temp);
8422
8423 xpath_stack swapped_stack = {stack.temp, stack.result};
8424
8425 xpath_string s = _left->eval_string(c, swapped_stack);
8426 xpath_string p = _right->eval_string(c, swapped_stack);
8427
8428 const char_t* pos = find_substring(s.c_str(), p.c_str());
8429
8430 return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string();
8431 }
8432
8433 case ast_func_substring_after:
8434 {
8435 xpath_allocator_capture cr(stack.temp);
8436
8437 xpath_stack swapped_stack = {stack.temp, stack.result};
8438
8439 xpath_string s = _left->eval_string(c, swapped_stack);
8440 xpath_string p = _right->eval_string(c, swapped_stack);
8441
8442 const char_t* pos = find_substring(s.c_str(), p.c_str());
8443 if (!pos) return xpath_string();
8444
8445 const char_t* result = pos + p.length();
8446
8447 return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result);
8448 }
8449
8450 case ast_func_substring_2:
8451 {
8452 xpath_allocator_capture cr(stack.temp);
8453
8454 xpath_stack swapped_stack = {stack.temp, stack.result};
8455
8456 xpath_string s = _left->eval_string(c, swapped_stack);
8457 size_t s_length = s.length();
8458
8459 double first = round_nearest(_right->eval_number(c, stack));
8460
8461 if (is_nan(first)) return xpath_string(); // NaN
8462 else if (first >= s_length + 1) return xpath_string();
8463
8464 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
8465 assert(1 <= pos && pos <= s_length + 1);
8466
8467 const char_t* rbegin = s.c_str() + (pos - 1);
8468
8469 return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin);
8470 }
8471
8472 case ast_func_substring_3:
8473 {
8474 xpath_allocator_capture cr(stack.temp);
8475
8476 xpath_stack swapped_stack = {stack.temp, stack.result};
8477
8478 xpath_string s = _left->eval_string(c, swapped_stack);
8479 size_t s_length = s.length();
8480
8481 double first = round_nearest(_right->eval_number(c, stack));
8482 double last = first + round_nearest(_right->_next->eval_number(c, stack));
8483
8484 if (is_nan(first) || is_nan(last)) return xpath_string();
8485 else if (first >= s_length + 1) return xpath_string();
8486 else if (first >= last) return xpath_string();
8487 else if (last < 1) return xpath_string();
8488
8489 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
8490 size_t end = last >= s_length + 1 ? s_length + 1 : static_cast<size_t>(last);
8491
8492 assert(1 <= pos && pos <= end && end <= s_length + 1);
8493 const char_t* rbegin = s.c_str() + (pos - 1);
8494 const char_t* rend = s.c_str() + (end - 1);
8495
8496 return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin) : xpath_string(rbegin, rend, stack.result);
8497 }
8498
8499 case ast_func_normalize_space_0:
8500 {
8501 xpath_string s = string_value(c.n, stack.result);
8502
8503 normalize_space(s.data(stack.result));
8504
8505 return s;
8506 }
8507
8508 case ast_func_normalize_space_1:
8509 {
8510 xpath_string s = _left->eval_string(c, stack);
8511
8512 normalize_space(s.data(stack.result));
8513
8514 return s;
8515 }
8516
8517 case ast_func_translate:
8518 {
8519 xpath_allocator_capture cr(stack.temp);
8520
8521 xpath_stack swapped_stack = {stack.temp, stack.result};
8522
8523 xpath_string s = _left->eval_string(c, stack);
8524 xpath_string from = _right->eval_string(c, swapped_stack);
8525 xpath_string to = _right->_next->eval_string(c, swapped_stack);
8526
8527 translate(s.data(stack.result), from.c_str(), to.c_str());
8528
8529 return s;
8530 }
8531
8532 case ast_variable:
8533 {
8534 assert(_rettype == _data.variable->type());
8535
8536 if (_rettype == xpath_type_string)
8537 return xpath_string_const(_data.variable->get_string());
8538
8539 // fallthrough to type conversion
8540 }
8541
8542 default:
8543 {
8544 switch (_rettype)
8545 {
8546 case xpath_type_boolean:
8547 return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
8548
8549 case xpath_type_number:
8550 return convert_number_to_string(eval_number(c, stack), stack.result);
8551
8552 case xpath_type_node_set:
8553 {
8554 xpath_allocator_capture cr(stack.temp);
8555
8556 xpath_stack swapped_stack = {stack.temp, stack.result};
8557
8558 xpath_node_set_raw ns = eval_node_set(c, swapped_stack);
8559 return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);
8560 }
8561
8562 default:
8563 assert(!"Wrong expression for return type string");
8564 return xpath_string();
8565 }
8566 }
8567 }
8568 }
8569
8570 xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack)
8571 {
8572 switch (_type)
8573 {
8574 case ast_op_union:
8575 {
8576 xpath_allocator_capture cr(stack.temp);
8577
8578 xpath_stack swapped_stack = {stack.temp, stack.result};
8579
8580 xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack);
8581 xpath_node_set_raw rs = _right->eval_node_set(c, stack);
8582
8583 // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother
8584 rs.set_type(xpath_node_set::type_unsorted);
8585
8586 rs.append(ls.begin(), ls.end(), stack.result);
8587 rs.remove_duplicates();
8588
8589 return rs;
8590 }
8591
8592 case ast_filter:
8593 case ast_filter_posinv:
8594 {
8595 xpath_node_set_raw set = _left->eval_node_set(c, stack);
8596
8597 // either expression is a number or it contains position() call; sort by document order
8598 if (_type == ast_filter) set.sort_do();
8599
8600 apply_predicate(set, 0, _right, stack);
8601
8602 return set;
8603 }
8604
8605 case ast_func_id:
8606 return xpath_node_set_raw();
8607
8608 case ast_step:
8609 {
8610 switch (_axis)
8611 {
8612 case axis_ancestor:
8613 return step_do(c, stack, axis_to_type<axis_ancestor>());
8614
8615 case axis_ancestor_or_self:
8616 return step_do(c, stack, axis_to_type<axis_ancestor_or_self>());
8617
8618 case axis_attribute:
8619 return step_do(c, stack, axis_to_type<axis_attribute>());
8620
8621 case axis_child:
8622 return step_do(c, stack, axis_to_type<axis_child>());
8623
8624 case axis_descendant:
8625 return step_do(c, stack, axis_to_type<axis_descendant>());
8626
8627 case axis_descendant_or_self:
8628 return step_do(c, stack, axis_to_type<axis_descendant_or_self>());
8629
8630 case axis_following:
8631 return step_do(c, stack, axis_to_type<axis_following>());
8632
8633 case axis_following_sibling:
8634 return step_do(c, stack, axis_to_type<axis_following_sibling>());
8635
8636 case axis_namespace:
8637 // namespaced axis is not supported
8638 return xpath_node_set_raw();
8639
8640 case axis_parent:
8641 return step_do(c, stack, axis_to_type<axis_parent>());
8642
8643 case axis_preceding:
8644 return step_do(c, stack, axis_to_type<axis_preceding>());
8645
8646 case axis_preceding_sibling:
8647 return step_do(c, stack, axis_to_type<axis_preceding_sibling>());
8648
8649 case axis_self:
8650 return step_do(c, stack, axis_to_type<axis_self>());
8651
8652 default:
8653 assert(!"Unknown axis");
8654 return xpath_node_set_raw();
8655 }
8656 }
8657
8658 case ast_step_root:
8659 {
8660 assert(!_right); // root step can't have any predicates
8661
8662 xpath_node_set_raw ns;
8663
8664 ns.set_type(xpath_node_set::type_sorted);
8665
8666 if (c.n.node()) ns.push_back(c.n.node().root(), stack.result);
8667 else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result);
8668
8669 return ns;
8670 }
8671
8672 case ast_variable:
8673 {
8674 assert(_rettype == _data.variable->type());
8675
8676 if (_rettype == xpath_type_node_set)
8677 {
8678 const xpath_node_set& s = _data.variable->get_node_set();
8679
8680 xpath_node_set_raw ns;
8681
8682 ns.set_type(s.type());
8683 ns.append(s.begin(), s.end(), stack.result);
8684
8685 return ns;
8686 }
8687
8688 // fallthrough to type conversion
8689 }
8690
8691 default:
8692 assert(!"Wrong expression for return type node set");
8693 return xpath_node_set_raw();
8694 }
8695 }
8696
8697 bool is_posinv()
8698 {
8699 switch (_type)
8700 {
8701 case ast_func_position:
8702 return false;
8703
8704 case ast_string_constant:
8705 case ast_number_constant:
8706 case ast_variable:
8707 return true;
8708
8709 case ast_step:
8710 case ast_step_root:
8711 return true;
8712
8713 case ast_predicate:
8714 case ast_filter:
8715 case ast_filter_posinv:
8716 return true;
8717
8718 default:
8719 if (_left && !_left->is_posinv()) return false;
8720
8721 for (xpath_ast_node* n = _right; n; n = n->_next)
8722 if (!n->is_posinv()) return false;
8723
8724 return true;
8725 }
8726 }
8727
8728 xpath_value_type rettype() const
8729 {
8730 return static_cast<xpath_value_type>(_rettype);
8731 }
8732 };
8733
8734 struct xpath_parser
8735 {
8736 xpath_allocator* _alloc;
8737 xpath_lexer _lexer;
8738
8739 const char_t* _query;
8740 xpath_variable_set* _variables;
8741
8742 xpath_parse_result* _result;
8743
8744 #ifdef PUGIXML_NO_EXCEPTIONS
8745 jmp_buf _error_handler;
8746 #endif
8747
8748 void throw_error(const char* message)
8749 {
8750 _result->error = message;
8751 _result->offset = _lexer.current_pos() - _query;
8752
8753 #ifdef PUGIXML_NO_EXCEPTIONS
8754 longjmp(_error_handler, 1);
8755 #else
8756 throw xpath_exception(*_result);
8757 #endif
8758 }
8759
8760 void throw_error_oom()
8761 {
8762 #ifdef PUGIXML_NO_EXCEPTIONS
8763 throw_error("Out of memory");
8764 #else
8765 throw std::bad_alloc();
8766 #endif
8767 }
8768
8769 void* alloc_node()
8770 {
8771 void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node));
8772
8773 if (!result) throw_error_oom();
8774
8775 return result;
8776 }
8777
8778 const char_t* alloc_string(const xpath_lexer_string& value)
8779 {
8780 if (value.begin)
8781 {
8782 size_t length = static_cast<size_t>(value.end - value.begin);
8783
8784 char_t* c = static_cast<char_t*>(_alloc->allocate_nothrow((length + 1) * sizeof(char_t)));
8785 if (!c) throw_error_oom();
8786
8787 memcpy(c, value.begin, length * sizeof(char_t));
8788 c[length] = 0;
8789
8790 return c;
8791 }
8792 else return 0;
8793 }
8794
8795 xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2])
8796 {
8797 assert(argc <= 1);
8798
8799 if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
8800
8801 return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]);
8802 }
8803
8804 xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2])
8805 {
8806 switch (name.begin[0])
8807 {
8808 case 'b':
8809 if (name == PUGIXML_TEXT("boolean") && argc == 1)
8810 return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]);
8811
8812 break;
8813
8814 case 'c':
8815 if (name == PUGIXML_TEXT("count") && argc == 1)
8816 {
8817 if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
8818 return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]);
8819 }
8820 else if (name == PUGIXML_TEXT("contains") && argc == 2)
8821 return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_string, args[0], args[1]);
8822 else if (name == PUGIXML_TEXT("concat") && argc >= 2)
8823 return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]);
8824 else if (name == PUGIXML_TEXT("ceiling") && argc == 1)
8825 return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]);
8826
8827 break;
8828
8829 case 'f':
8830 if (name == PUGIXML_TEXT("false") && argc == 0)
8831 return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean);
8832 else if (name == PUGIXML_TEXT("floor") && argc == 1)
8833 return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]);
8834
8835 break;
8836
8837 case 'i':
8838 if (name == PUGIXML_TEXT("id") && argc == 1)
8839 return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]);
8840
8841 break;
8842
8843 case 'l':
8844 if (name == PUGIXML_TEXT("last") && argc == 0)
8845 return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number);
8846 else if (name == PUGIXML_TEXT("lang") && argc == 1)
8847 return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]);
8848 else if (name == PUGIXML_TEXT("local-name") && argc <= 1)
8849 return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args);
8850
8851 break;
8852
8853 case 'n':
8854 if (name == PUGIXML_TEXT("name") && argc <= 1)
8855 return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args);
8856 else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1)
8857 return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args);
8858 else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1)
8859 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]);
8860 else if (name == PUGIXML_TEXT("not") && argc == 1)
8861 return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]);
8862 else if (name == PUGIXML_TEXT("number") && argc <= 1)
8863 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);
8864
8865 break;
8866
8867 case 'p':
8868 if (name == PUGIXML_TEXT("position") && argc == 0)
8869 return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number);
8870
8871 break;
8872
8873 case 'r':
8874 if (name == PUGIXML_TEXT("round") && argc == 1)
8875 return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]);
8876
8877 break;
8878
8879 case 's':
8880 if (name == PUGIXML_TEXT("string") && argc <= 1)
8881 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);
8882 else if (name == PUGIXML_TEXT("string-length") && argc <= 1)
8883 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_string, args[0]);
8884 else if (name == PUGIXML_TEXT("starts-with") && argc == 2)
8885 return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
8886 else if (name == PUGIXML_TEXT("substring-before") && argc == 2)
8887 return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);
8888 else if (name == PUGIXML_TEXT("substring-after") && argc == 2)
8889 return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);
8890 else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3))
8891 return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]);
8892 else if (name == PUGIXML_TEXT("sum") && argc == 1)
8893 {
8894 if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
8895 return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]);
8896 }
8897
8898 break;
8899
8900 case 't':
8901 if (name == PUGIXML_TEXT("translate") && argc == 3)
8902 return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]);
8903 else if (name == PUGIXML_TEXT("true") && argc == 0)
8904 return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean);
8905
8906 break;
8907
8908 default:
8909 break;
8910 }
8911
8912 throw_error("Unrecognized function or wrong parameter count");
8913
8914 return 0;
8915 }
8916
8917 axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified)
8918 {
8919 specified = true;
8920
8921 switch (name.begin[0])
8922 {
8923 case 'a':
8924 if (name == PUGIXML_TEXT("ancestor"))
8925 return axis_ancestor;
8926 else if (name == PUGIXML_TEXT("ancestor-or-self"))
8927 return axis_ancestor_or_self;
8928 else if (name == PUGIXML_TEXT("attribute"))
8929 return axis_attribute;
8930
8931 break;
8932
8933 case 'c':
8934 if (name == PUGIXML_TEXT("child"))
8935 return axis_child;
8936
8937 break;
8938
8939 case 'd':
8940 if (name == PUGIXML_TEXT("descendant"))
8941 return axis_descendant;
8942 else if (name == PUGIXML_TEXT("descendant-or-self"))
8943 return axis_descendant_or_self;
8944
8945 break;
8946
8947 case 'f':
8948 if (name == PUGIXML_TEXT("following"))
8949 return axis_following;
8950 else if (name == PUGIXML_TEXT("following-sibling"))
8951 return axis_following_sibling;
8952
8953 break;
8954
8955 case 'n':
8956 if (name == PUGIXML_TEXT("namespace"))
8957 return axis_namespace;
8958
8959 break;
8960
8961 case 'p':
8962 if (name == PUGIXML_TEXT("parent"))
8963 return axis_parent;
8964 else if (name == PUGIXML_TEXT("preceding"))
8965 return axis_preceding;
8966 else if (name == PUGIXML_TEXT("preceding-sibling"))
8967 return axis_preceding_sibling;
8968
8969 break;
8970
8971 case 's':
8972 if (name == PUGIXML_TEXT("self"))
8973 return axis_self;
8974
8975 break;
8976
8977 default:
8978 break;
8979 }
8980
8981 specified = false;
8982 return axis_child;
8983 }
8984
8985 nodetest_t parse_node_test_type(const xpath_lexer_string& name)
8986 {
8987 switch (name.begin[0])
8988 {
8989 case 'c':
8990 if (name == PUGIXML_TEXT("comment"))
8991 return nodetest_type_comment;
8992
8993 break;
8994
8995 case 'n':
8996 if (name == PUGIXML_TEXT("node"))
8997 return nodetest_type_node;
8998
8999 break;
9000
9001 case 'p':
9002 if (name == PUGIXML_TEXT("processing-instruction"))
9003 return nodetest_type_pi;
9004
9005 break;
9006
9007 case 't':
9008 if (name == PUGIXML_TEXT("text"))
9009 return nodetest_type_text;
9010
9011 break;
9012
9013 default:
9014 break;
9015 }
9016
9017 return nodetest_none;
9018 }
9019
9020 // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
9021 xpath_ast_node* parse_primary_expression()
9022 {
9023 switch (_lexer.current())
9024 {
9025 case lex_var_ref:
9026 {
9027 xpath_lexer_string name = _lexer.contents();
9028
9029 if (!_variables)
9030 throw_error("Unknown variable: variable set is not provided");
9031
9032 xpath_variable* var = get_variable(_variables, name.begin, name.end);
9033
9034 if (!var)
9035 throw_error("Unknown variable: variable set does not contain the given name");
9036
9037 _lexer.next();
9038
9039 return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var);
9040 }
9041
9042 case lex_open_brace:
9043 {
9044 _lexer.next();
9045
9046 xpath_ast_node* n = parse_expression();
9047
9048 if (_lexer.current() != lex_close_brace)
9049 throw_error("Unmatched braces");
9050
9051 _lexer.next();
9052
9053 return n;
9054 }
9055
9056 case lex_quoted_string:
9057 {
9058 const char_t* value = alloc_string(_lexer.contents());
9059
9060 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value);
9061 _lexer.next();
9062
9063 return n;
9064 }
9065
9066 case lex_number:
9067 {
9068 double value = 0;
9069
9070 if (!convert_string_to_number(_lexer.contents().begin, _lexer.contents().end, &value))
9071 throw_error_oom();
9072
9073 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value);
9074 _lexer.next();
9075
9076 return n;
9077 }
9078
9079 case lex_string:
9080 {
9081 xpath_ast_node* args[2] = {0};
9082 size_t argc = 0;
9083
9084 xpath_lexer_string function = _lexer.contents();
9085 _lexer.next();
9086
9087 xpath_ast_node* last_arg = 0;
9088
9089 if (_lexer.current() != lex_open_brace)
9090 throw_error("Unrecognized function call");
9091 _lexer.next();
9092
9093 if (_lexer.current() != lex_close_brace)
9094 args[argc++] = parse_expression();
9095
9096 while (_lexer.current() != lex_close_brace)
9097 {
9098 if (_lexer.current() != lex_comma)
9099 throw_error("No comma between function arguments");
9100 _lexer.next();
9101
9102 xpath_ast_node* n = parse_expression();
9103
9104 if (argc < 2) args[argc] = n;
9105 else last_arg->set_next(n);
9106
9107 argc++;
9108 last_arg = n;
9109 }
9110
9111 _lexer.next();
9112
9113 return parse_function(function, argc, args);
9114 }
9115
9116 default:
9117 throw_error("Unrecognizable primary expression");
9118
9119 return 0;
9120 }
9121 }
9122
9123 // FilterExpr ::= PrimaryExpr | FilterExpr Predicate
9124 // Predicate ::= '[' PredicateExpr ']'
9125 // PredicateExpr ::= Expr
9126 xpath_ast_node* parse_filter_expression()
9127 {
9128 xpath_ast_node* n = parse_primary_expression();
9129
9130 while (_lexer.current() == lex_open_square_brace)
9131 {
9132 _lexer.next();
9133
9134 xpath_ast_node* expr = parse_expression();
9135
9136 if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set");
9137
9138 bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv();
9139
9140 n = new (alloc_node()) xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr);
9141
9142 if (_lexer.current() != lex_close_square_brace)
9143 throw_error("Unmatched square brace");
9144
9145 _lexer.next();
9146 }
9147
9148 return n;
9149 }
9150
9151 // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
9152 // AxisSpecifier ::= AxisName '::' | '@'?
9153 // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'
9154 // NameTest ::= '*' | NCName ':' '*' | QName
9155 // AbbreviatedStep ::= '.' | '..'
9156 xpath_ast_node* parse_step(xpath_ast_node* set)
9157 {
9158 if (set && set->rettype() != xpath_type_node_set)
9159 throw_error("Step has to be applied to node set");
9160
9161 bool axis_specified = false;
9162 axis_t axis = axis_child; // implied child axis
9163
9164 if (_lexer.current() == lex_axis_attribute)
9165 {
9166 axis = axis_attribute;
9167 axis_specified = true;
9168
9169 _lexer.next();
9170 }
9171 else if (_lexer.current() == lex_dot)
9172 {
9173 _lexer.next();
9174
9175 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0);
9176 }
9177 else if (_lexer.current() == lex_double_dot)
9178 {
9179 _lexer.next();
9180
9181 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0);
9182 }
9183
9184 nodetest_t nt_type = nodetest_none;
9185 xpath_lexer_string nt_name;
9186
9187 if (_lexer.current() == lex_string)
9188 {
9189 // node name test
9190 nt_name = _lexer.contents();
9191 _lexer.next();
9192
9193 // was it an axis name?
9194 if (_lexer.current() == lex_double_colon)
9195 {
9196 // parse axis name
9197 if (axis_specified) throw_error("Two axis specifiers in one step");
9198
9199 axis = parse_axis_name(nt_name, axis_specified);
9200
9201 if (!axis_specified) throw_error("Unknown axis");
9202
9203 // read actual node test
9204 _lexer.next();
9205
9206 if (_lexer.current() == lex_multiply)
9207 {
9208 nt_type = nodetest_all;
9209 nt_name = xpath_lexer_string();
9210 _lexer.next();
9211 }
9212 else if (_lexer.current() == lex_string)
9213 {
9214 nt_name = _lexer.contents();
9215 _lexer.next();
9216 }
9217 else throw_error("Unrecognized node test");
9218 }
9219
9220 if (nt_type == nodetest_none)
9221 {
9222 // node type test or processing-instruction
9223 if (_lexer.current() == lex_open_brace)
9224 {
9225 _lexer.next();
9226
9227 if (_lexer.current() == lex_close_brace)
9228 {
9229 _lexer.next();
9230
9231 nt_type = parse_node_test_type(nt_name);
9232
9233 if (nt_type == nodetest_none) throw_error("Unrecognized node type");
9234
9235 nt_name = xpath_lexer_string();
9236 }
9237 else if (nt_name == PUGIXML_TEXT("processing-instruction"))
9238 {
9239 if (_lexer.current() != lex_quoted_string)
9240 throw_error("Only literals are allowed as arguments to processing-instruction()");
9241
9242 nt_type = nodetest_pi;
9243 nt_name = _lexer.contents();
9244 _lexer.next();
9245
9246 if (_lexer.current() != lex_close_brace)
9247 throw_error("Unmatched brace near processing-instruction()");
9248 _lexer.next();
9249 }
9250 else
9251 throw_error("Unmatched brace near node type test");
9252
9253 }
9254 // QName or NCName:*
9255 else
9256 {
9257 if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:*
9258 {
9259 nt_name.end--; // erase *
9260
9261 nt_type = nodetest_all_in_namespace;
9262 }
9263 else nt_type = nodetest_name;
9264 }
9265 }
9266 }
9267 else if (_lexer.current() == lex_multiply)
9268 {
9269 nt_type = nodetest_all;
9270 _lexer.next();
9271 }
9272 else throw_error("Unrecognized node test");
9273
9274 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name));
9275
9276 xpath_ast_node* last = 0;
9277
9278 while (_lexer.current() == lex_open_square_brace)
9279 {
9280 _lexer.next();
9281
9282 xpath_ast_node* expr = parse_expression();
9283
9284 xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr);
9285
9286 if (_lexer.current() != lex_close_square_brace)
9287 throw_error("Unmatched square brace");
9288 _lexer.next();
9289
9290 if (last) last->set_next(pred);
9291 else n->set_right(pred);
9292
9293 last = pred;
9294 }
9295
9296 return n;
9297 }
9298
9299 // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
9300 xpath_ast_node* parse_relative_location_path(xpath_ast_node* set)
9301 {
9302 xpath_ast_node* n = parse_step(set);
9303
9304 while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
9305 {
9306 lexeme_t l = _lexer.current();
9307 _lexer.next();
9308
9309 if (l == lex_double_slash)
9310 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
9311
9312 n = parse_step(n);
9313 }
9314
9315 return n;
9316 }
9317
9318 // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
9319 // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
9320 xpath_ast_node* parse_location_path()
9321 {
9322 if (_lexer.current() == lex_slash)
9323 {
9324 _lexer.next();
9325
9326 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
9327
9328 // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path
9329 lexeme_t l = _lexer.current();
9330
9331 if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
9332 return parse_relative_location_path(n);
9333 else
9334 return n;
9335 }
9336 else if (_lexer.current() == lex_double_slash)
9337 {
9338 _lexer.next();
9339
9340 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
9341 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
9342
9343 return parse_relative_location_path(n);
9344 }
9345
9346 // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1
9347 return parse_relative_location_path(0);
9348 }
9349
9350 // PathExpr ::= LocationPath
9351 // | FilterExpr
9352 // | FilterExpr '/' RelativeLocationPath
9353 // | FilterExpr '//' RelativeLocationPath
9354 xpath_ast_node* parse_path_expression()
9355 {
9356 // Clarification.
9357 // PathExpr begins with either LocationPath or FilterExpr.
9358 // FilterExpr begins with PrimaryExpr
9359 // PrimaryExpr begins with '$' in case of it being a variable reference,
9360 // '(' in case of it being an expression, string literal, number constant or
9361 // function call.
9362
9363 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace ||
9364 _lexer.current() == lex_quoted_string || _lexer.current() == lex_number ||
9365 _lexer.current() == lex_string)
9366 {
9367 if (_lexer.current() == lex_string)
9368 {
9369 // This is either a function call, or not - if not, we shall proceed with location path
9370 const char_t* state = _lexer.state();
9371
9372 while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
9373
9374 if (*state != '(') return parse_location_path();
9375
9376 // This looks like a function call; however this still can be a node-test. Check it.
9377 if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path();
9378 }
9379
9380 xpath_ast_node* n = parse_filter_expression();
9381
9382 if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
9383 {
9384 lexeme_t l = _lexer.current();
9385 _lexer.next();
9386
9387 if (l == lex_double_slash)
9388 {
9389 if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set");
9390
9391 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
9392 }
9393
9394 // select from location path
9395 return parse_relative_location_path(n);
9396 }
9397
9398 return n;
9399 }
9400 else return parse_location_path();
9401 }
9402
9403 // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
9404 xpath_ast_node* parse_union_expression()
9405 {
9406 xpath_ast_node* n = parse_path_expression();
9407
9408 while (_lexer.current() == lex_union)
9409 {
9410 _lexer.next();
9411
9412 xpath_ast_node* expr = parse_union_expression();
9413
9414 if (n->rettype() != xpath_type_node_set || expr->rettype() != xpath_type_node_set)
9415 throw_error("Union operator has to be applied to node sets");
9416
9417 n = new (alloc_node()) xpath_ast_node(ast_op_union, xpath_type_node_set, n, expr);
9418 }
9419
9420 return n;
9421 }
9422
9423 // UnaryExpr ::= UnionExpr | '-' UnaryExpr
9424 xpath_ast_node* parse_unary_expression()
9425 {
9426 if (_lexer.current() == lex_minus)
9427 {
9428 _lexer.next();
9429
9430 xpath_ast_node* expr = parse_unary_expression();
9431
9432 return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr);
9433 }
9434 else return parse_union_expression();
9435 }
9436
9437 // MultiplicativeExpr ::= UnaryExpr
9438 // | MultiplicativeExpr '*' UnaryExpr
9439 // | MultiplicativeExpr 'div' UnaryExpr
9440 // | MultiplicativeExpr 'mod' UnaryExpr
9441 xpath_ast_node* parse_multiplicative_expression()
9442 {
9443 xpath_ast_node* n = parse_unary_expression();
9444
9445 while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string &&
9446 (_lexer.contents() == PUGIXML_TEXT("mod") || _lexer.contents() == PUGIXML_TEXT("div"))))
9447 {
9448 ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply :
9449 _lexer.contents().begin[0] == 'd' ? ast_op_divide : ast_op_mod;
9450 _lexer.next();
9451
9452 xpath_ast_node* expr = parse_unary_expression();
9453
9454 n = new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, expr);
9455 }
9456
9457 return n;
9458 }
9459
9460 // AdditiveExpr ::= MultiplicativeExpr
9461 // | AdditiveExpr '+' MultiplicativeExpr
9462 // | AdditiveExpr '-' MultiplicativeExpr
9463 xpath_ast_node* parse_additive_expression()
9464 {
9465 xpath_ast_node* n = parse_multiplicative_expression();
9466
9467 while (_lexer.current() == lex_plus || _lexer.current() == lex_minus)
9468 {
9469 lexeme_t l = _lexer.current();
9470
9471 _lexer.next();
9472
9473 xpath_ast_node* expr = parse_multiplicative_expression();
9474
9475 n = new (alloc_node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, xpath_type_number, n, expr);
9476 }
9477
9478 return n;
9479 }
9480
9481 // RelationalExpr ::= AdditiveExpr
9482 // | RelationalExpr '<' AdditiveExpr
9483 // | RelationalExpr '>' AdditiveExpr
9484 // | RelationalExpr '<=' AdditiveExpr
9485 // | RelationalExpr '>=' AdditiveExpr
9486 xpath_ast_node* parse_relational_expression()
9487 {
9488 xpath_ast_node* n = parse_additive_expression();
9489
9490 while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal ||
9491 _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal)
9492 {
9493 lexeme_t l = _lexer.current();
9494 _lexer.next();
9495
9496 xpath_ast_node* expr = parse_additive_expression();
9497
9498 n = new (alloc_node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater :
9499 l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, xpath_type_boolean, n, expr);
9500 }
9501
9502 return n;
9503 }
9504
9505 // EqualityExpr ::= RelationalExpr
9506 // | EqualityExpr '=' RelationalExpr
9507 // | EqualityExpr '!=' RelationalExpr
9508 xpath_ast_node* parse_equality_expression()
9509 {
9510 xpath_ast_node* n = parse_relational_expression();
9511
9512 while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal)
9513 {
9514 lexeme_t l = _lexer.current();
9515
9516 _lexer.next();
9517
9518 xpath_ast_node* expr = parse_relational_expression();
9519
9520 n = new (alloc_node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, xpath_type_boolean, n, expr);
9521 }
9522
9523 return n;
9524 }
9525
9526 // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
9527 xpath_ast_node* parse_and_expression()
9528 {
9529 xpath_ast_node* n = parse_equality_expression();
9530
9531 while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("and"))
9532 {
9533 _lexer.next();
9534
9535 xpath_ast_node* expr = parse_equality_expression();
9536
9537 n = new (alloc_node()) xpath_ast_node(ast_op_and, xpath_type_boolean, n, expr);
9538 }
9539
9540 return n;
9541 }
9542
9543 // OrExpr ::= AndExpr | OrExpr 'or' AndExpr
9544 xpath_ast_node* parse_or_expression()
9545 {
9546 xpath_ast_node* n = parse_and_expression();
9547
9548 while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("or"))
9549 {
9550 _lexer.next();
9551
9552 xpath_ast_node* expr = parse_and_expression();
9553
9554 n = new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, n, expr);
9555 }
9556
9557 return n;
9558 }
9559
9560 // Expr ::= OrExpr
9561 xpath_ast_node* parse_expression()
9562 {
9563 return parse_or_expression();
9564 }
9565
9566 xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result)
9567 {
9568 }
9569
9570 xpath_ast_node* parse()
9571 {
9572 xpath_ast_node* result = parse_expression();
9573
9574 if (_lexer.current() != lex_eof)
9575 {
9576 // there are still unparsed tokens left, error
9577 throw_error("Incorrect query");
9578 }
9579
9580 return result;
9581 }
9582
9583 static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result)
9584 {
9585 xpath_parser parser(query, variables, alloc, result);
9586
9587 #ifdef PUGIXML_NO_EXCEPTIONS
9588 int error = setjmp(parser._error_handler);
9589
9590 return (error == 0) ? parser.parse() : 0;
9591 #else
9592 return parser.parse();
9593 #endif
9594 }
9595 };
9596
9597 struct xpath_query_impl
9598 {
9599 static xpath_query_impl* create()
9600 {
9601 void* memory = xml_memory::allocate(sizeof(xpath_query_impl));
9602
9603 return new (memory) xpath_query_impl();
9604 }
9605
9606 static void destroy(void* ptr)
9607 {
9608 if (!ptr) return;
9609
9610 // free all allocated pages
9611 static_cast<xpath_query_impl*>(ptr)->alloc.release();
9612
9613 // free allocator memory (with the first page)
9614 xml_memory::deallocate(ptr);
9615 }
9616
9617 xpath_query_impl(): root(0), alloc(&block)
9618 {
9619 block.next = 0;
9620 }
9621
9622 xpath_ast_node* root;
9623 xpath_allocator alloc;
9624 xpath_memory_block block;
9625 };
9626
9627 PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd)
9628 {
9629 if (!impl) return xpath_string();
9630
9631 #ifdef PUGIXML_NO_EXCEPTIONS
9632 if (setjmp(sd.error_handler)) return xpath_string();
9633 #endif
9634
9635 xpath_context c(n, 1, 1);
9636
9637 return impl->root->eval_string(c, sd.stack);
9638 }
9639PUGI__NS_END
9640
9641namespace pugi
9642{
9643#ifndef PUGIXML_NO_EXCEPTIONS
9644 PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_)
9645 {
9646 assert(_result.error);
9647 }
9648
9649 PUGI__FN const char* xpath_exception::what() const throw()
9650 {
9651 return _result.error;
9652 }
9653
9654 PUGI__FN const xpath_parse_result& xpath_exception::result() const
9655 {
9656 return _result;
9657 }
9658#endif
9659
9660 PUGI__FN xpath_node::xpath_node()
9661 {
9662 }
9663
9664 PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_)
9665 {
9666 }
9667
9668 PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
9669 {
9670 }
9671
9672 PUGI__FN xml_node xpath_node::node() const
9673 {
9674 return _attribute ? xml_node() : _node;
9675 }
9676
9677 PUGI__FN xml_attribute xpath_node::attribute() const
9678 {
9679 return _attribute;
9680 }
9681
9682 PUGI__FN xml_node xpath_node::parent() const
9683 {
9684 return _attribute ? _node : _node.parent();
9685 }
9686
9687 PUGI__FN static void unspecified_bool_xpath_node(xpath_node***)
9688 {
9689 }
9690
9691 PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const
9692 {
9693 return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
9694 }
9695
9696 PUGI__FN bool xpath_node::operator!() const
9697 {
9698 return !(_node || _attribute);
9699 }
9700
9701 PUGI__FN bool xpath_node::operator==(const xpath_node& n) const
9702 {
9703 return _node == n._node && _attribute == n._attribute;
9704 }
9705
9706 PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const
9707 {
9708 return _node != n._node || _attribute != n._attribute;
9709 }
9710
9711#ifdef __BORLANDC__
9712 PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs)
9713 {
9714 return (bool)lhs && rhs;
9715 }
9716
9717 PUGI__FN bool operator||(const xpath_node& lhs, bool rhs)
9718 {
9719 return (bool)lhs || rhs;
9720 }
9721#endif
9722
9723 PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_)
9724 {
9725 assert(begin_ <= end_);
9726
9727 size_t size_ = static_cast<size_t>(end_ - begin_);
9728
9729 if (size_ <= 1)
9730 {
9731 // deallocate old buffer
9732 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
9733
9734 // use internal buffer
9735 if (begin_ != end_) _storage = *begin_;
9736
9737 _begin = &_storage;
9738 _end = &_storage + size_;
9739 }
9740 else
9741 {
9742 // make heap copy
9743 xpath_node* storage = static_cast<xpath_node*>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));
9744
9745 if (!storage)
9746 {
9747 #ifdef PUGIXML_NO_EXCEPTIONS
9748 return;
9749 #else
9750 throw std::bad_alloc();
9751 #endif
9752 }
9753
9754 memcpy(storage, begin_, size_ * sizeof(xpath_node));
9755
9756 // deallocate old buffer
9757 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
9758
9759 // finalize
9760 _begin = storage;
9761 _end = storage + size_;
9762 }
9763 }
9764
9765 PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage)
9766 {
9767 }
9768
9769 PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_), _begin(&_storage), _end(&_storage)
9770 {
9771 _assign(begin_, end_);
9772 }
9773
9774 PUGI__FN xpath_node_set::~xpath_node_set()
9775 {
9776 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
9777 }
9778
9779 PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage)
9780 {
9781 _assign(ns._begin, ns._end);
9782 }
9783
9784 PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns)
9785 {
9786 if (this == &ns) return *this;
9787
9788 _type = ns._type;
9789 _assign(ns._begin, ns._end);
9790
9791 return *this;
9792 }
9793
9794 PUGI__FN xpath_node_set::type_t xpath_node_set::type() const
9795 {
9796 return _type;
9797 }
9798
9799 PUGI__FN size_t xpath_node_set::size() const
9800 {
9801 return _end - _begin;
9802 }
9803
9804 PUGI__FN bool xpath_node_set::empty() const
9805 {
9806 return _begin == _end;
9807 }
9808
9809 PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const
9810 {
9811 assert(index < size());
9812 return _begin[index];
9813 }
9814
9815 PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const
9816 {
9817 return _begin;
9818 }
9819
9820 PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const
9821 {
9822 return _end;
9823 }
9824
9825 PUGI__FN void xpath_node_set::sort(bool reverse)
9826 {
9827 _type = impl::xpath_sort(_begin, _end, _type, reverse);
9828 }
9829
9830 PUGI__FN xpath_node xpath_node_set::first() const
9831 {
9832 return impl::xpath_first(_begin, _end, _type);
9833 }
9834
9835 PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0)
9836 {
9837 }
9838
9839 PUGI__FN xpath_parse_result::operator bool() const
9840 {
9841 return error == 0;
9842 }
9843
9844 PUGI__FN const char* xpath_parse_result::description() const
9845 {
9846 return error ? error : "No error";
9847 }
9848
9849 PUGI__FN xpath_variable::xpath_variable()
9850 {
9851 }
9852
9853 PUGI__FN const char_t* xpath_variable::name() const
9854 {
9855 switch (_type)
9856 {
9857 case xpath_type_node_set:
9858 return static_cast<const impl::xpath_variable_node_set*>(this)->name;
9859
9860 case xpath_type_number:
9861 return static_cast<const impl::xpath_variable_number*>(this)->name;
9862
9863 case xpath_type_string:
9864 return static_cast<const impl::xpath_variable_string*>(this)->name;
9865
9866 case xpath_type_boolean:
9867 return static_cast<const impl::xpath_variable_boolean*>(this)->name;
9868
9869 default:
9870 assert(!"Invalid variable type");
9871 return 0;
9872 }
9873 }
9874
9875 PUGI__FN xpath_value_type xpath_variable::type() const
9876 {
9877 return _type;
9878 }
9879
9880 PUGI__FN bool xpath_variable::get_boolean() const
9881 {
9882 return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false;
9883 }
9884
9885 PUGI__FN double xpath_variable::get_number() const
9886 {
9887 return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number*>(this)->value : impl::gen_nan();
9888 }
9889
9890 PUGI__FN const char_t* xpath_variable::get_string() const
9891 {
9892 const char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(this)->value : 0;
9893 return value ? value : PUGIXML_TEXT("");
9894 }
9895
9896 PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const
9897 {
9898 return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set;
9899 }
9900
9901 PUGI__FN bool xpath_variable::set(bool value)
9902 {
9903 if (_type != xpath_type_boolean) return false;
9904
9905 static_cast<impl::xpath_variable_boolean*>(this)->value = value;
9906 return true;
9907 }
9908
9909 PUGI__FN bool xpath_variable::set(double value)
9910 {
9911 if (_type != xpath_type_number) return false;
9912
9913 static_cast<impl::xpath_variable_number*>(this)->value = value;
9914 return true;
9915 }
9916
9917 PUGI__FN bool xpath_variable::set(const char_t* value)
9918 {
9919 if (_type != xpath_type_string) return false;
9920
9921 impl::xpath_variable_string* var = static_cast<impl::xpath_variable_string*>(this);
9922
9923 // duplicate string
9924 size_t size = (impl::strlength(value) + 1) * sizeof(char_t);
9925
9926 char_t* copy = static_cast<char_t*>(impl::xml_memory::allocate(size));
9927 if (!copy) return false;
9928
9929 memcpy(copy, value, size);
9930
9931 // replace old string
9932 if (var->value) impl::xml_memory::deallocate(var->value);
9933 var->value = copy;
9934
9935 return true;
9936 }
9937
9938 PUGI__FN bool xpath_variable::set(const xpath_node_set& value)
9939 {
9940 if (_type != xpath_type_node_set) return false;
9941
9942 static_cast<impl::xpath_variable_node_set*>(this)->value = value;
9943 return true;
9944 }
9945
9946 PUGI__FN xpath_variable_set::xpath_variable_set()
9947 {
9948 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0;
9949 }
9950
9951 PUGI__FN xpath_variable_set::~xpath_variable_set()
9952 {
9953 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
9954 {
9955 xpath_variable* var = _data[i];
9956
9957 while (var)
9958 {
9959 xpath_variable* next = var->_next;
9960
9961 impl::delete_xpath_variable(var->_type, var);
9962
9963 var = next;
9964 }
9965 }
9966 }
9967
9968 PUGI__FN xpath_variable* xpath_variable_set::find(const char_t* name) const
9969 {
9970 const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
9971 size_t hash = impl::hash_string(name) % hash_size;
9972
9973 // look for existing variable
9974 for (xpath_variable* var = _data[hash]; var; var = var->_next)
9975 if (impl::strequal(var->name(), name))
9976 return var;
9977
9978 return 0;
9979 }
9980
9981 PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type)
9982 {
9983 const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
9984 size_t hash = impl::hash_string(name) % hash_size;
9985
9986 // look for existing variable
9987 for (xpath_variable* var = _data[hash]; var; var = var->_next)
9988 if (impl::strequal(var->name(), name))
9989 return var->type() == type ? var : 0;
9990
9991 // add new variable
9992 xpath_variable* result = impl::new_xpath_variable(type, name);
9993
9994 if (result)
9995 {
9996 result->_type = type;
9997 result->_next = _data[hash];
9998
9999 _data[hash] = result;
10000 }
10001
10002 return result;
10003 }
10004
10005 PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value)
10006 {
10007 xpath_variable* var = add(name, xpath_type_boolean);
10008 return var ? var->set(value) : false;
10009 }
10010
10011 PUGI__FN bool xpath_variable_set::set(const char_t* name, double value)
10012 {
10013 xpath_variable* var = add(name, xpath_type_number);
10014 return var ? var->set(value) : false;
10015 }
10016
10017 PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value)
10018 {
10019 xpath_variable* var = add(name, xpath_type_string);
10020 return var ? var->set(value) : false;
10021 }
10022
10023 PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)
10024 {
10025 xpath_variable* var = add(name, xpath_type_node_set);
10026 return var ? var->set(value) : false;
10027 }
10028
10029 PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name)
10030 {
10031 return find(name);
10032 }
10033
10034 PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const
10035 {
10036 return find(name);
10037 }
10038
10039 PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)
10040 {
10041 impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
10042
10043 if (!qimpl)
10044 {
10045 #ifdef PUGIXML_NO_EXCEPTIONS
10046 _result.error = "Out of memory";
10047 #else
10048 throw std::bad_alloc();
10049 #endif
10050 }
10051 else
10052 {
10053 impl::buffer_holder impl_holder(qimpl, impl::xpath_query_impl::destroy);
10054
10055 qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
10056
10057 if (qimpl->root)
10058 {
10059 _impl = static_cast<impl::xpath_query_impl*>(impl_holder.release());
10060 _result.error = 0;
10061 }
10062 }
10063 }
10064
10065 PUGI__FN xpath_query::~xpath_query()
10066 {
10067 impl::xpath_query_impl::destroy(_impl);
10068 }
10069
10070 PUGI__FN xpath_value_type xpath_query::return_type() const
10071 {
10072 if (!_impl) return xpath_type_none;
10073
10074 return static_cast<impl::xpath_query_impl*>(_impl)->root->rettype();
10075 }
10076
10077 PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const
10078 {
10079 if (!_impl) return false;
10080
10081 impl::xpath_context c(n, 1, 1);
10082 impl::xpath_stack_data sd;
10083
10084 #ifdef PUGIXML_NO_EXCEPTIONS
10085 if (setjmp(sd.error_handler)) return false;
10086 #endif
10087
10088 return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);
10089 }
10090
10091 PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const
10092 {
10093 if (!_impl) return impl::gen_nan();
10094
10095 impl::xpath_context c(n, 1, 1);
10096 impl::xpath_stack_data sd;
10097
10098 #ifdef PUGIXML_NO_EXCEPTIONS
10099 if (setjmp(sd.error_handler)) return impl::gen_nan();
10100 #endif
10101
10102 return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);
10103 }
10104
10105#ifndef PUGIXML_NO_STL
10106 PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const
10107 {
10108 impl::xpath_stack_data sd;
10109
10110 return impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd).c_str();
10111 }
10112#endif
10113
10114 PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const
10115 {
10116 impl::xpath_stack_data sd;
10117
10118 impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd);
10119
10120 size_t full_size = r.length() + 1;
10121
10122 if (capacity > 0)
10123 {
10124 size_t size = (full_size < capacity) ? full_size : capacity;
10125 assert(size > 0);
10126
10127 memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
10128 buffer[size - 1] = 0;
10129 }
10130
10131 return full_size;
10132 }
10133
10134 PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const
10135 {
10136 if (!_impl) return xpath_node_set();
10137
10138 impl::xpath_ast_node* root = static_cast<impl::xpath_query_impl*>(_impl)->root;
10139
10140 if (root->rettype() != xpath_type_node_set)
10141 {
10142 #ifdef PUGIXML_NO_EXCEPTIONS
10143 return xpath_node_set();
10144 #else
10145 xpath_parse_result res;
10146 res.error = "Expression does not evaluate to node set";
10147
10148 throw xpath_exception(res);
10149 #endif
10150 }
10151
10152 impl::xpath_context c(n, 1, 1);
10153 impl::xpath_stack_data sd;
10154
10155 #ifdef PUGIXML_NO_EXCEPTIONS
10156 if (setjmp(sd.error_handler)) return xpath_node_set();
10157 #endif
10158
10159 impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack);
10160
10161 return xpath_node_set(r.begin(), r.end(), r.type());
10162 }
10163
10164 PUGI__FN const xpath_parse_result& xpath_query::result() const
10165 {
10166 return _result;
10167 }
10168
10169 PUGI__FN static void unspecified_bool_xpath_query(xpath_query***)
10170 {
10171 }
10172
10173 PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const
10174 {
10175 return _impl ? unspecified_bool_xpath_query : 0;
10176 }
10177
10178 PUGI__FN bool xpath_query::operator!() const
10179 {
10180 return !_impl;
10181 }
10182
10183 PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const
10184 {
10185 xpath_query q(query, variables);
10186 return select_single_node(q);
10187 }
10188
10189 PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const
10190 {
10191 xpath_node_set s = query.evaluate_node_set(*this);
10192 return s.empty() ? xpath_node() : s.first();
10193 }
10194
10195 PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const
10196 {
10197 xpath_query q(query, variables);
10198 return select_nodes(q);
10199 }
10200
10201 PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const
10202 {
10203 return query.evaluate_node_set(*this);
10204 }
10205}
10206
10207#endif
10208
10209#ifdef __BORLANDC__
10210# pragma option pop
10211#endif
10212
10213// Intel C++ does not properly keep warning state for function templates,
10214// so popping warning state at the end of translation unit leads to warnings in the middle.
10215#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
10216# pragma warning(pop)
10217#endif
10218
10219// Undefine all local macros (makes sure we're not leaking macros in header-only mode)
10220#undef PUGI__NO_INLINE
10221#undef PUGI__STATIC_ASSERT
10222#undef PUGI__DMC_VOLATILE
10223#undef PUGI__MSVC_CRT_VERSION
10224#undef PUGI__NS_BEGIN
10225#undef PUGI__NS_END
10226#undef PUGI__FN
10227#undef PUGI__FN_NO_INLINE
10228#undef PUGI__IS_CHARTYPE_IMPL
10229#undef PUGI__IS_CHARTYPE
10230#undef PUGI__IS_CHARTYPEX
10231#undef PUGI__SKIPWS
10232#undef PUGI__OPTSET
10233#undef PUGI__PUSHNODE
10234#undef PUGI__POPNODE
10235#undef PUGI__SCANFOR
10236#undef PUGI__SCANWHILE
10237#undef PUGI__ENDSEG
10238#undef PUGI__THROW_ERROR
10239#undef PUGI__CHECK_ERROR
10240
10241#endif
10242
10243/**
10244 * Copyright (c) 2006-2012 Arseny Kapoulkine
10245 *
10246 * Permission is hereby granted, free of charge, to any person
10247 * obtaining a copy of this software and associated documentation
10248 * files (the "Software"), to deal in the Software without
10249 * restriction, including without limitation the rights to use,
10250 * copy, modify, merge, publish, distribute, sublicense, and/or sell
10251 * copies of the Software, and to permit persons to whom the
10252 * Software is furnished to do so, subject to the following
10253 * conditions:
10254 *
10255 * The above copyright notice and this permission notice shall be
10256 * included in all copies or substantial portions of the Software.
10257 *
10258 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
10259 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
10260 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
10261 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
10262 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
10263 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
10264 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
10265 * OTHER DEALINGS IN THE SOFTWARE.
10266 */
10267