Changeset 33a694 for ThirdParty/vmg/src/thirdparty/pugixml/pugixml.cpp
- Timestamp:
- May 5, 2017, 2:17:23 PM (8 years ago)
- Branches:
- Action_Thermostats, Add_AtomRandomPerturbation, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_StructOpt_integration_tests, AutomationFragmentation_failures, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph_documentation, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, Fix_ChronosMutex, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, GeometryObjects, Gui_displays_atomic_force_velocity, IndependentFragmentGrids_IntegrationTest, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, RotateToPrincipalAxisSystem_UndoRedo, StoppableMakroAction, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, Ubuntu_1604_changes
- Children:
- dde50d
- Parents:
- 6798a5
- git-author:
- Frederik Heber <heber@…> (04/05/17 17:17:45)
- git-committer:
- Frederik Heber <frederik.heber@…> (05/05/17 14:17:23)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
ThirdParty/vmg/src/thirdparty/pugixml/pugixml.cpp
r6798a5 r33a694 1 1 /** 2 * pugixml parser - version 1. 02 * pugixml parser - version 1.8 3 3 * -------------------------------------------------------- 4 * Copyright (C) 2006-201 0, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)4 * Copyright (C) 2006-2016, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) 5 5 * Report bugs and download new versions at http://pugixml.org/ 6 6 * … … 12 12 */ 13 13 14 #ifndef SOURCE_PUGIXML_CPP 15 #define SOURCE_PUGIXML_CPP 16 14 17 #include "pugixml.hpp" 15 18 … … 18 21 #include <string.h> 19 22 #include <assert.h> 20 #include <setjmp.h> 21 #include <wchar.h> 23 #include <limits.h> 24 25 #ifdef PUGIXML_WCHAR_MODE 26 # include <wchar.h> 27 #endif 22 28 23 29 #ifndef PUGIXML_NO_XPATH 24 30 # include <math.h> 25 31 # include <float.h> 32 # ifdef PUGIXML_NO_EXCEPTIONS 33 # include <setjmp.h> 34 # endif 26 35 #endif 27 36 … … 36 45 37 46 #ifdef _MSC_VER 47 # pragma warning(push) 38 48 # pragma warning(disable: 4127) // conditional expression is constant 39 49 # pragma warning(disable: 4324) // structure was padded due to __declspec(align()) … … 41 51 # pragma warning(disable: 4702) // unreachable code 42 52 # pragma warning(disable: 4996) // this function or variable may be unsafe 53 # pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged 43 54 #endif 44 55 45 56 #ifdef __INTEL_COMPILER 46 # pragma warning(disable: 177) // function was declared but never referenced 57 # pragma warning(disable: 177) // function was declared but never referenced 47 58 # pragma warning(disable: 279) // controlling expression is constant 48 59 # pragma warning(disable: 1478 1786) // function was declared "deprecated" 60 # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type 49 61 #endif 50 62 63 #if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY) 64 # pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away 65 #endif 66 51 67 #ifdef __BORLANDC__ 68 # pragma option push 52 69 # pragma warn -8008 // condition is always false 53 70 # pragma warn -8066 // unreachable code … … 55 72 56 73 #ifdef __SNC__ 74 // Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug 57 75 # pragma diag_suppress=178 // function was declared but never referenced 58 76 # pragma diag_suppress=237 // controlling expression is constant 59 77 #endif 60 78 61 // uintptr_t62 #if !defined(_MSC_VER) || _MSC_VER >= 160063 # include <stdint.h>64 #else65 # if _MSC_VER < 130066 // No native uintptr_t in MSVC667 typedef size_t uintptr_t;68 # endif69 typedef unsigned __int8 uint8_t;70 typedef unsigned __int16 uint16_t;71 typedef unsigned __int32 uint32_t;72 typedef __int32 int32_t;73 #endif74 75 79 // Inlining controls 76 80 #if defined(_MSC_VER) && _MSC_VER >= 1300 77 # define PUGI XML_NO_INLINE __declspec(noinline)81 # define PUGI__NO_INLINE __declspec(noinline) 78 82 #elif defined(__GNUC__) 79 # define PUGI XML_NO_INLINE __attribute__((noinline))83 # define PUGI__NO_INLINE __attribute__((noinline)) 80 84 #else 81 # define PUGI XML_NO_INLINE85 # define PUGI__NO_INLINE 82 86 #endif 83 87 88 // Branch weight controls 89 #if defined(__GNUC__) 90 # define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0) 91 #else 92 # define PUGI__UNLIKELY(cond) (cond) 93 #endif 94 84 95 // Simple static assertion 85 #define STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }96 #define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; } 86 97 87 98 // Digital Mars C++ bug workaround for passing char loaded from memory via stack 88 99 #ifdef __DMC__ 89 # define DMC_VOLATILE volatile100 # define PUGI__DMC_VOLATILE volatile 90 101 #else 91 # define DMC_VOLATILE102 # define PUGI__DMC_VOLATILE 92 103 #endif 93 104 94 using namespace pugi; 105 // 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) 106 #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST) 107 using std::memcpy; 108 using std::memmove; 109 using std::memset; 110 #endif 111 112 // Some MinGW versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions in strict ANSI mode 113 #if defined(PUGIXML_HAS_LONG_LONG) && defined(__MINGW32__) && defined(__STRICT_ANSI__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX) 114 # define LLONG_MAX 9223372036854775807LL 115 # define LLONG_MIN (-LLONG_MAX-1) 116 # define ULLONG_MAX (2ULL*LLONG_MAX+1) 117 #endif 118 119 // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features 120 #if defined(_MSC_VER) && !defined(__S3E__) 121 # define PUGI__MSVC_CRT_VERSION _MSC_VER 122 #endif 123 124 #ifdef PUGIXML_HEADER_ONLY 125 # define PUGI__NS_BEGIN namespace pugi { namespace impl { 126 # define PUGI__NS_END } } 127 # define PUGI__FN inline 128 # define PUGI__FN_NO_INLINE inline 129 #else 130 # if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces 131 # define PUGI__NS_BEGIN namespace pugi { namespace impl { 132 # define PUGI__NS_END } } 133 # else 134 # define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace { 135 # define PUGI__NS_END } } } 136 # endif 137 # define PUGI__FN 138 # define PUGI__FN_NO_INLINE PUGI__NO_INLINE 139 #endif 140 141 // uintptr_t 142 #if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561) 143 namespace pugi 144 { 145 # ifndef _UINTPTR_T_DEFINED 146 typedef size_t uintptr_t; 147 # endif 148 149 typedef unsigned __int8 uint8_t; 150 typedef unsigned __int16 uint16_t; 151 typedef unsigned __int32 uint32_t; 152 } 153 #else 154 # include <stdint.h> 155 #endif 95 156 96 157 // Memory allocation 97 namespace 98 { 99 void* default_allocate(size_t size) 158 PUGI__NS_BEGIN 159 PUGI__FN void* default_allocate(size_t size) 100 160 { 101 161 return malloc(size); 102 162 } 103 163 104 void default_deallocate(void* ptr)164 PUGI__FN void default_deallocate(void* ptr) 105 165 { 106 166 free(ptr); 107 167 } 108 168 109 allocation_function global_allocate = default_allocate; 110 deallocation_function global_deallocate = default_deallocate; 111 } 169 template <typename T> 170 struct xml_memory_management_function_storage 171 { 172 static allocation_function allocate; 173 static deallocation_function deallocate; 174 }; 175 176 // Global allocation functions are stored in class statics so that in header mode linker deduplicates them 177 // Without a template<> we'll get multiple definitions of the same static 178 template <typename T> allocation_function xml_memory_management_function_storage<T>::allocate = default_allocate; 179 template <typename T> deallocation_function xml_memory_management_function_storage<T>::deallocate = default_deallocate; 180 181 typedef xml_memory_management_function_storage<int> xml_memory; 182 PUGI__NS_END 112 183 113 184 // String utilities 114 namespace 115 { 185 PUGI__NS_BEGIN 116 186 // Get string length 117 size_t strlength(const char_t* s)187 PUGI__FN size_t strlength(const char_t* s) 118 188 { 119 189 assert(s); … … 127 197 128 198 // Compare two strings 129 bool strequal(const char_t* src, const char_t* dst)199 PUGI__FN bool strequal(const char_t* src, const char_t* dst) 130 200 { 131 201 assert(src && dst); … … 139 209 140 210 // Compare lhs with [rhs_begin, rhs_end) 141 bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)211 PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) 142 212 { 143 213 for (size_t i = 0; i < count; ++i) 144 214 if (lhs[i] != rhs[i]) 145 215 return false; 146 216 147 217 return lhs[count] == 0; 148 218 } 149 150 #ifdef PUGIXML_WCHAR_MODE 151 // Convert string to wide string, assuming all symbols are ASCII 152 void widen_ascii(wchar_t* dest, const char* source) 153 { 154 for (const char* i = source; *i; ++i) *dest++ = *i; 155 *dest = 0; 156 } 157 #endif 158 } 159 160 #if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH) 161 // auto_ptr-like buffer holder for exception recovery 162 namespace 163 { 164 struct buffer_holder 165 { 166 void* data; 167 void (*deleter)(void*); 168 169 buffer_holder(void* data, void (*deleter)(void*)): data(data), deleter(deleter) 170 { 171 } 172 173 ~buffer_holder() 219 220 // Get length of wide string, even if CRT lacks wide character support 221 PUGI__FN size_t strlength_wide(const wchar_t* s) 222 { 223 assert(s); 224 225 #ifdef PUGIXML_WCHAR_MODE 226 return wcslen(s); 227 #else 228 const wchar_t* end = s; 229 while (*end) end++; 230 return static_cast<size_t>(end - s); 231 #endif 232 } 233 PUGI__NS_END 234 235 // auto_ptr-like object for exception recovery 236 PUGI__NS_BEGIN 237 template <typename T> struct auto_deleter 238 { 239 typedef void (*D)(T*); 240 241 T* data; 242 D deleter; 243 244 auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_) 245 { 246 } 247 248 ~auto_deleter() 174 249 { 175 250 if (data) deleter(data); 176 251 } 177 252 178 void* release()179 { 180 void* result = data;253 T* release() 254 { 255 T* result = data; 181 256 data = 0; 182 257 return result; 183 258 } 184 259 }; 185 } 260 PUGI__NS_END 261 262 #ifdef PUGIXML_COMPACT 263 PUGI__NS_BEGIN 264 class compact_hash_table 265 { 266 public: 267 compact_hash_table(): _items(0), _capacity(0), _count(0) 268 { 269 } 270 271 void clear() 272 { 273 if (_items) 274 { 275 xml_memory::deallocate(_items); 276 _items = 0; 277 _capacity = 0; 278 _count = 0; 279 } 280 } 281 282 void** find(const void* key) 283 { 284 assert(key); 285 286 if (_capacity == 0) return 0; 287 288 size_t hashmod = _capacity - 1; 289 size_t bucket = hash(key) & hashmod; 290 291 for (size_t probe = 0; probe <= hashmod; ++probe) 292 { 293 item_t& probe_item = _items[bucket]; 294 295 if (probe_item.key == key) 296 return &probe_item.value; 297 298 if (probe_item.key == 0) 299 return 0; 300 301 // hash collision, quadratic probing 302 bucket = (bucket + probe + 1) & hashmod; 303 } 304 305 assert(false && "Hash table is full"); 306 return 0; 307 } 308 309 void** insert(const void* key) 310 { 311 assert(key); 312 assert(_capacity != 0 && _count < _capacity - _capacity / 4); 313 314 size_t hashmod = _capacity - 1; 315 size_t bucket = hash(key) & hashmod; 316 317 for (size_t probe = 0; probe <= hashmod; ++probe) 318 { 319 item_t& probe_item = _items[bucket]; 320 321 if (probe_item.key == 0) 322 { 323 probe_item.key = key; 324 _count++; 325 return &probe_item.value; 326 } 327 328 if (probe_item.key == key) 329 return &probe_item.value; 330 331 // hash collision, quadratic probing 332 bucket = (bucket + probe + 1) & hashmod; 333 } 334 335 assert(false && "Hash table is full"); 336 return 0; 337 } 338 339 bool reserve() 340 { 341 if (_count + 16 >= _capacity - _capacity / 4) 342 return rehash(); 343 344 return true; 345 } 346 347 private: 348 struct item_t 349 { 350 const void* key; 351 void* value; 352 }; 353 354 item_t* _items; 355 size_t _capacity; 356 357 size_t _count; 358 359 bool rehash(); 360 361 static unsigned int hash(const void* key) 362 { 363 unsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key)); 364 365 // MurmurHash3 32-bit finalizer 366 h ^= h >> 16; 367 h *= 0x85ebca6bu; 368 h ^= h >> 13; 369 h *= 0xc2b2ae35u; 370 h ^= h >> 16; 371 372 return h; 373 } 374 }; 375 376 PUGI__FN_NO_INLINE bool compact_hash_table::rehash() 377 { 378 compact_hash_table rt; 379 rt._capacity = (_capacity == 0) ? 32 : _capacity * 2; 380 rt._items = static_cast<item_t*>(xml_memory::allocate(sizeof(item_t) * rt._capacity)); 381 382 if (!rt._items) 383 return false; 384 385 memset(rt._items, 0, sizeof(item_t) * rt._capacity); 386 387 for (size_t i = 0; i < _capacity; ++i) 388 if (_items[i].key) 389 *rt.insert(_items[i].key) = _items[i].value; 390 391 if (_items) 392 xml_memory::deallocate(_items); 393 394 _capacity = rt._capacity; 395 _items = rt._items; 396 397 assert(_count == rt._count); 398 399 return true; 400 } 401 402 PUGI__NS_END 186 403 #endif 187 404 188 namespace 189 { 190 static const size_t xml_memory_page_size = 32768; 191 192 static const uintptr_t xml_memory_page_alignment = 32; 193 static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); 194 static const uintptr_t xml_memory_page_name_allocated_mask = 16; 195 static const uintptr_t xml_memory_page_value_allocated_mask = 8; 196 static const uintptr_t xml_memory_page_type_mask = 7; 405 PUGI__NS_BEGIN 406 #ifdef PUGIXML_COMPACT 407 static const uintptr_t xml_memory_block_alignment = 4; 408 #else 409 static const uintptr_t xml_memory_block_alignment = sizeof(void*); 410 #endif 411 412 // extra metadata bits 413 static const uintptr_t xml_memory_page_contents_shared_mask = 64; 414 static const uintptr_t xml_memory_page_name_allocated_mask = 32; 415 static const uintptr_t xml_memory_page_value_allocated_mask = 16; 416 static const uintptr_t xml_memory_page_type_mask = 15; 417 418 // combined masks for string uniqueness 419 static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; 420 static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; 421 422 #ifdef PUGIXML_COMPACT 423 #define PUGI__GETHEADER_IMPL(object, page, flags) // unused 424 #define PUGI__GETPAGE_IMPL(header) (header).get_page() 425 #else 426 #define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags)) 427 // this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings 428 #define PUGI__GETPAGE_IMPL(header) static_cast<impl::xml_memory_page*>(const_cast<void*>(static_cast<const void*>(reinterpret_cast<const char*>(&header) - (header >> 8)))) 429 #endif 430 431 #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header) 432 #define PUGI__NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask) 197 433 198 434 struct xml_allocator; … … 202 438 static xml_memory_page* construct(void* memory) 203 439 { 204 if (!memory) return 0; //$ redundant, left for performance205 206 440 xml_memory_page* result = static_cast<xml_memory_page*>(memory); 207 441 208 442 result->allocator = 0; 209 result->memory = 0;210 443 result->prev = 0; 211 444 result->next = 0; … … 213 446 result->freed_size = 0; 214 447 448 #ifdef PUGIXML_COMPACT 449 result->compact_string_base = 0; 450 result->compact_shared_parent = 0; 451 result->compact_page_marker = 0; 452 #endif 453 215 454 return result; 216 455 } 217 456 218 457 xml_allocator* allocator; 219 220 void* memory;221 458 222 459 xml_memory_page* prev; … … 226 463 size_t freed_size; 227 464 228 char data[1]; 465 #ifdef PUGIXML_COMPACT 466 char_t* compact_string_base; 467 void* compact_shared_parent; 468 uint32_t* compact_page_marker; 469 #endif 229 470 }; 471 472 static const size_t xml_memory_page_size = 473 #ifdef PUGIXML_MEMORY_PAGE_SIZE 474 (PUGIXML_MEMORY_PAGE_SIZE) 475 #else 476 32768 477 #endif 478 - sizeof(xml_memory_page); 230 479 231 480 struct xml_memory_string_header … … 239 488 xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size) 240 489 { 490 #ifdef PUGIXML_COMPACT 491 _hash = 0; 492 #endif 241 493 } 242 494 243 495 xml_memory_page* allocate_page(size_t data_size) 244 496 { 245 size_t size = offsetof(xml_memory_page, data) + data_size;497 size_t size = sizeof(xml_memory_page) + data_size; 246 498 247 499 // allocate block with some alignment, leaving memory for worst-case padding 248 void* memory = global_allocate(size + xml_memory_page_alignment);500 void* memory = xml_memory::allocate(size); 249 501 if (!memory) return 0; 250 502 251 // align upwards to page boundary252 void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1));253 254 503 // prepare page structure 255 xml_memory_page* page = xml_memory_page::construct( page_memory);256 257 page->memory = memory; 504 xml_memory_page* page = xml_memory_page::construct(memory); 505 assert(page); 506 258 507 page->allocator = _root->allocator; 259 508 … … 263 512 static void deallocate_page(xml_memory_page* page) 264 513 { 265 global_deallocate(page->memory);514 xml_memory::deallocate(page); 266 515 } 267 516 … … 270 519 void* allocate_memory(size_t size, xml_memory_page*& out_page) 271 520 { 272 if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page); 273 274 void* buf = _root->data + _busy_size; 521 if (PUGI__UNLIKELY(_busy_size + size > xml_memory_page_size)) 522 return allocate_memory_oob(size, out_page); 523 524 void* buf = reinterpret_cast<char*>(_root) + sizeof(xml_memory_page) + _busy_size; 275 525 276 526 _busy_size += size; … … 281 531 } 282 532 533 #ifdef PUGIXML_COMPACT 534 void* allocate_object(size_t size, xml_memory_page*& out_page) 535 { 536 void* result = allocate_memory(size + sizeof(uint32_t), out_page); 537 if (!result) return 0; 538 539 // adjust for marker 540 ptrdiff_t offset = static_cast<char*>(result) - reinterpret_cast<char*>(out_page->compact_page_marker); 541 542 if (PUGI__UNLIKELY(static_cast<uintptr_t>(offset) >= 256 * xml_memory_block_alignment)) 543 { 544 // insert new marker 545 uint32_t* marker = static_cast<uint32_t*>(result); 546 547 *marker = static_cast<uint32_t>(reinterpret_cast<char*>(marker) - reinterpret_cast<char*>(out_page)); 548 out_page->compact_page_marker = marker; 549 550 // since we don't reuse the page space until we reallocate it, we can just pretend that we freed the marker block 551 // this will make sure deallocate_memory correctly tracks the size 552 out_page->freed_size += sizeof(uint32_t); 553 554 return marker + 1; 555 } 556 else 557 { 558 // roll back uint32_t part 559 _busy_size -= sizeof(uint32_t); 560 561 return result; 562 } 563 } 564 #else 565 void* allocate_object(size_t size, xml_memory_page*& out_page) 566 { 567 return allocate_memory(size, out_page); 568 } 569 #endif 570 283 571 void deallocate_memory(void* ptr, size_t size, xml_memory_page* page) 284 572 { 285 573 if (page == _root) page->busy_size = _busy_size; 286 574 287 assert(ptr >= page->data && ptr < page->data+ page->busy_size);575 assert(ptr >= reinterpret_cast<char*>(page) + sizeof(xml_memory_page) && ptr < reinterpret_cast<char*>(page) + sizeof(xml_memory_page) + page->busy_size); 288 576 (void)!ptr; 289 577 … … 298 586 299 587 // top page freed, just reset sizes 300 page->busy_size = page->freed_size = 0; 588 page->busy_size = 0; 589 page->freed_size = 0; 590 591 #ifdef PUGIXML_COMPACT 592 // reset compact state to maximize efficiency 593 page->compact_string_base = 0; 594 page->compact_shared_parent = 0; 595 page->compact_page_marker = 0; 596 #endif 597 301 598 _busy_size = 0; 302 599 } … … 318 615 char_t* allocate_string(size_t length) 319 616 { 617 static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment; 618 619 PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset); 620 320 621 // allocate memory for string and header block 321 622 size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); 322 323 // round size up to pointeralignment boundary324 size_t full_size = (size + ( sizeof(void*) - 1)) & ~(sizeof(void*)- 1);623 624 // round size up to block alignment boundary 625 size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1); 325 626 326 627 xml_memory_page* page; … … 330 631 331 632 // setup header 332 ptrdiff_t page_offset = reinterpret_cast<char*>(header) - page->data; 333 334 assert(page_offset >= 0 && page_offset < (1 << 16)); 335 header->page_offset = static_cast<uint16_t>(page_offset); 633 ptrdiff_t page_offset = reinterpret_cast<char*>(header) - reinterpret_cast<char*>(page) - sizeof(xml_memory_page); 634 635 assert(page_offset % xml_memory_block_alignment == 0); 636 assert(page_offset >= 0 && static_cast<size_t>(page_offset) < max_encoded_offset); 637 header->page_offset = static_cast<uint16_t>(static_cast<size_t>(page_offset) / xml_memory_block_alignment); 336 638 337 639 // full_size == 0 for large strings that occupy the whole page 338 assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0)); 339 header->full_size = static_cast<uint16_t>(full_size < (1 << 16) ? full_size : 0); 340 341 return reinterpret_cast<char_t*>(header + 1); 640 assert(full_size % xml_memory_block_alignment == 0); 641 assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0)); 642 header->full_size = static_cast<uint16_t>(full_size < max_encoded_offset ? full_size / xml_memory_block_alignment : 0); 643 644 // round-trip through void* to avoid 'cast increases required alignment of target type' warning 645 // header is guaranteed a pointer-sized alignment, which should be enough for char_t 646 return static_cast<char_t*>(static_cast<void*>(header + 1)); 342 647 } 343 648 344 649 void deallocate_string(char_t* string) 345 650 { 651 // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings 652 // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string 653 346 654 // get header 347 xml_memory_string_header* header = reinterpret_cast<xml_memory_string_header*>(string) - 1; 655 xml_memory_string_header* header = static_cast<xml_memory_string_header*>(static_cast<void*>(string)) - 1; 656 assert(header); 348 657 349 658 // deallocate 350 size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset;351 xml_memory_page* page = reinterpret_cast<xml_memory_page*>( reinterpret_cast<char*>(header) - page_offset);659 size_t page_offset = sizeof(xml_memory_page) + header->page_offset * xml_memory_block_alignment; 660 xml_memory_page* page = reinterpret_cast<xml_memory_page*>(static_cast<void*>(reinterpret_cast<char*>(header) - page_offset)); 352 661 353 662 // if full_size == 0 then this string occupies the whole page 354 size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size ;663 size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * xml_memory_block_alignment; 355 664 356 665 deallocate_memory(header, full_size, page); 666 } 667 668 bool reserve() 669 { 670 #ifdef PUGIXML_COMPACT 671 return _hash->reserve(); 672 #else 673 return true; 674 #endif 357 675 } 358 676 359 677 xml_memory_page* _root; 360 678 size_t _busy_size; 679 680 #ifdef PUGIXML_COMPACT 681 compact_hash_table* _hash; 682 #endif 361 683 }; 362 684 363 PUGI XML_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page)685 PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page) 364 686 { 365 687 const size_t large_allocation_threshold = xml_memory_page_size / 4; 366 688 367 689 xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size); 690 out_page = page; 691 368 692 if (!page) return 0; 369 693 … … 390 714 _root->prev->next = page; 391 715 _root->prev = page; 392 } 393 394 // allocate inside page 395 page->busy_size = size; 396 397 out_page = page; 398 return page->data; 399 } 400 } 401 716 717 page->busy_size = size; 718 } 719 720 return reinterpret_cast<char*>(page) + sizeof(xml_memory_page); 721 } 722 PUGI__NS_END 723 724 #ifdef PUGIXML_COMPACT 725 PUGI__NS_BEGIN 726 static const uintptr_t compact_alignment_log2 = 2; 727 static const uintptr_t compact_alignment = 1 << compact_alignment_log2; 728 729 class compact_header 730 { 731 public: 732 compact_header(xml_memory_page* page, unsigned int flags) 733 { 734 PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment); 735 736 ptrdiff_t offset = (reinterpret_cast<char*>(this) - reinterpret_cast<char*>(page->compact_page_marker)); 737 assert(offset % compact_alignment == 0 && static_cast<uintptr_t>(offset) < 256 * compact_alignment); 738 739 _page = static_cast<unsigned char>(offset >> compact_alignment_log2); 740 _flags = static_cast<unsigned char>(flags); 741 } 742 743 void operator&=(uintptr_t mod) 744 { 745 _flags &= static_cast<unsigned char>(mod); 746 } 747 748 void operator|=(uintptr_t mod) 749 { 750 _flags |= static_cast<unsigned char>(mod); 751 } 752 753 uintptr_t operator&(uintptr_t mod) const 754 { 755 return _flags & mod; 756 } 757 758 xml_memory_page* get_page() const 759 { 760 // round-trip through void* to silence 'cast increases required alignment of target type' warnings 761 const char* page_marker = reinterpret_cast<const char*>(this) - (_page << compact_alignment_log2); 762 const char* page = page_marker - *reinterpret_cast<const uint32_t*>(static_cast<const void*>(page_marker)); 763 764 return const_cast<xml_memory_page*>(reinterpret_cast<const xml_memory_page*>(static_cast<const void*>(page))); 765 } 766 767 private: 768 unsigned char _page; 769 unsigned char _flags; 770 }; 771 772 PUGI__FN xml_memory_page* compact_get_page(const void* object, int header_offset) 773 { 774 const compact_header* header = reinterpret_cast<const compact_header*>(static_cast<const char*>(object) - header_offset); 775 776 return header->get_page(); 777 } 778 779 template <int header_offset, typename T> PUGI__FN_NO_INLINE T* compact_get_value(const void* object) 780 { 781 return static_cast<T*>(*compact_get_page(object, header_offset)->allocator->_hash->find(object)); 782 } 783 784 template <int header_offset, typename T> PUGI__FN_NO_INLINE void compact_set_value(const void* object, T* value) 785 { 786 *compact_get_page(object, header_offset)->allocator->_hash->insert(object) = value; 787 } 788 789 template <typename T, int header_offset, int start = -126> class compact_pointer 790 { 791 public: 792 compact_pointer(): _data(0) 793 { 794 } 795 796 void operator=(const compact_pointer& rhs) 797 { 798 *this = rhs + 0; 799 } 800 801 void operator=(T* value) 802 { 803 if (value) 804 { 805 // value is guaranteed to be compact-aligned; 'this' is not 806 // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*) 807 // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to 808 // compensate for arithmetic shift rounding for negative values 809 ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this); 810 ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) - start; 811 812 if (static_cast<uintptr_t>(offset) <= 253) 813 _data = static_cast<unsigned char>(offset + 1); 814 else 815 { 816 compact_set_value<header_offset>(this, value); 817 818 _data = 255; 819 } 820 } 821 else 822 _data = 0; 823 } 824 825 operator T*() const 826 { 827 if (_data) 828 { 829 if (_data < 255) 830 { 831 uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1); 832 833 return reinterpret_cast<T*>(base + ((_data - 1 + start) << compact_alignment_log2)); 834 } 835 else 836 return compact_get_value<header_offset, T>(this); 837 } 838 else 839 return 0; 840 } 841 842 T* operator->() const 843 { 844 return *this; 845 } 846 847 private: 848 unsigned char _data; 849 }; 850 851 template <typename T, int header_offset> class compact_pointer_parent 852 { 853 public: 854 compact_pointer_parent(): _data(0) 855 { 856 } 857 858 void operator=(const compact_pointer_parent& rhs) 859 { 860 *this = rhs + 0; 861 } 862 863 void operator=(T* value) 864 { 865 if (value) 866 { 867 // value is guaranteed to be compact-aligned; 'this' is not 868 // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*) 869 // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to 870 // compensate for arithmetic shift behavior for negative values 871 ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this); 872 ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) + 65533; 873 874 if (static_cast<uintptr_t>(offset) <= 65533) 875 { 876 _data = static_cast<unsigned short>(offset + 1); 877 } 878 else 879 { 880 xml_memory_page* page = compact_get_page(this, header_offset); 881 882 if (PUGI__UNLIKELY(page->compact_shared_parent == 0)) 883 page->compact_shared_parent = value; 884 885 if (page->compact_shared_parent == value) 886 { 887 _data = 65534; 888 } 889 else 890 { 891 compact_set_value<header_offset>(this, value); 892 893 _data = 65535; 894 } 895 } 896 } 897 else 898 { 899 _data = 0; 900 } 901 } 902 903 operator T*() const 904 { 905 if (_data) 906 { 907 if (_data < 65534) 908 { 909 uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1); 910 911 return reinterpret_cast<T*>(base + ((_data - 1 - 65533) << compact_alignment_log2)); 912 } 913 else if (_data == 65534) 914 return static_cast<T*>(compact_get_page(this, header_offset)->compact_shared_parent); 915 else 916 return compact_get_value<header_offset, T>(this); 917 } 918 else 919 return 0; 920 } 921 922 T* operator->() const 923 { 924 return *this; 925 } 926 927 private: 928 uint16_t _data; 929 }; 930 931 template <int header_offset, int base_offset> class compact_string 932 { 933 public: 934 compact_string(): _data(0) 935 { 936 } 937 938 void operator=(const compact_string& rhs) 939 { 940 *this = rhs + 0; 941 } 942 943 void operator=(char_t* value) 944 { 945 if (value) 946 { 947 xml_memory_page* page = compact_get_page(this, header_offset); 948 949 if (PUGI__UNLIKELY(page->compact_string_base == 0)) 950 page->compact_string_base = value; 951 952 ptrdiff_t offset = value - page->compact_string_base; 953 954 if (static_cast<uintptr_t>(offset) < (65535 << 7)) 955 { 956 // round-trip through void* to silence 'cast increases required alignment of target type' warnings 957 uint16_t* base = reinterpret_cast<uint16_t*>(static_cast<void*>(reinterpret_cast<char*>(this) - base_offset)); 958 959 if (*base == 0) 960 { 961 *base = static_cast<uint16_t>((offset >> 7) + 1); 962 _data = static_cast<unsigned char>((offset & 127) + 1); 963 } 964 else 965 { 966 ptrdiff_t remainder = offset - ((*base - 1) << 7); 967 968 if (static_cast<uintptr_t>(remainder) <= 253) 969 { 970 _data = static_cast<unsigned char>(remainder + 1); 971 } 972 else 973 { 974 compact_set_value<header_offset>(this, value); 975 976 _data = 255; 977 } 978 } 979 } 980 else 981 { 982 compact_set_value<header_offset>(this, value); 983 984 _data = 255; 985 } 986 } 987 else 988 { 989 _data = 0; 990 } 991 } 992 993 operator char_t*() const 994 { 995 if (_data) 996 { 997 if (_data < 255) 998 { 999 xml_memory_page* page = compact_get_page(this, header_offset); 1000 1001 // round-trip through void* to silence 'cast increases required alignment of target type' warnings 1002 const uint16_t* base = reinterpret_cast<const uint16_t*>(static_cast<const void*>(reinterpret_cast<const char*>(this) - base_offset)); 1003 assert(*base); 1004 1005 ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1); 1006 1007 return page->compact_string_base + offset; 1008 } 1009 else 1010 { 1011 return compact_get_value<header_offset, char_t>(this); 1012 } 1013 } 1014 else 1015 return 0; 1016 } 1017 1018 private: 1019 unsigned char _data; 1020 }; 1021 PUGI__NS_END 1022 #endif 1023 1024 #ifdef PUGIXML_COMPACT 402 1025 namespace pugi 403 1026 { 404 /// A 'name=value' XML attribute structure.405 1027 struct xml_attribute_struct 406 1028 { 407 /// Default ctor 408 xml_attribute_struct(xml_memory_page* page): header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) 409 { 410 } 411 412 uintptr_t header; 413 414 char_t* name; ///< Pointer to attribute name. 415 char_t* value; ///< Pointer to attribute value. 416 417 xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list) 418 xml_attribute_struct* next_attribute; ///< Next attribute 1029 xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0) 1030 { 1031 PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8); 1032 } 1033 1034 impl::compact_header header; 1035 1036 uint16_t namevalue_base; 1037 1038 impl::compact_string<4, 2> name; 1039 impl::compact_string<5, 3> value; 1040 1041 impl::compact_pointer<xml_attribute_struct, 6> prev_attribute_c; 1042 impl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute; 419 1043 }; 420 1044 421 /// An XML document tree node.422 1045 struct xml_node_struct 423 1046 { 424 /// Default ctor 425 /// \param type - node type 426 xml_node_struct(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) 427 { 428 } 429 430 uintptr_t header; 431 432 xml_node_struct* parent; ///< Pointer to parent 433 434 char_t* name; ///< Pointer to element name. 435 char_t* value; ///< Pointer to any associated string data. 436 437 xml_node_struct* first_child; ///< First child 438 439 xml_node_struct* prev_sibling_c; ///< Left brother (cyclic list) 440 xml_node_struct* next_sibling; ///< Right brother 441 442 xml_attribute_struct* first_attribute; ///< First attribute 1047 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0) 1048 { 1049 PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12); 1050 } 1051 1052 impl::compact_header header; 1053 1054 uint16_t namevalue_base; 1055 1056 impl::compact_string<4, 2> name; 1057 impl::compact_string<5, 3> value; 1058 1059 impl::compact_pointer_parent<xml_node_struct, 6> parent; 1060 1061 impl::compact_pointer<xml_node_struct, 8, 0> first_child; 1062 1063 impl::compact_pointer<xml_node_struct, 9> prev_sibling_c; 1064 impl::compact_pointer<xml_node_struct, 10, 0> next_sibling; 1065 1066 impl::compact_pointer<xml_attribute_struct, 11, 0> first_attribute; 443 1067 }; 444 1068 } 445 446 namespace 1069 #else 1070 namespace pugi 447 1071 { 1072 struct xml_attribute_struct 1073 { 1074 xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0) 1075 { 1076 header = PUGI__GETHEADER_IMPL(this, page, 0); 1077 } 1078 1079 uintptr_t header; 1080 1081 char_t* name; 1082 char_t* value; 1083 1084 xml_attribute_struct* prev_attribute_c; 1085 xml_attribute_struct* next_attribute; 1086 }; 1087 1088 struct xml_node_struct 1089 { 1090 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) 1091 { 1092 header = PUGI__GETHEADER_IMPL(this, page, type); 1093 } 1094 1095 uintptr_t header; 1096 1097 char_t* name; 1098 char_t* value; 1099 1100 xml_node_struct* parent; 1101 1102 xml_node_struct* first_child; 1103 1104 xml_node_struct* prev_sibling_c; 1105 xml_node_struct* next_sibling; 1106 1107 xml_attribute_struct* first_attribute; 1108 }; 1109 } 1110 #endif 1111 1112 PUGI__NS_BEGIN 1113 struct xml_extra_buffer 1114 { 1115 char_t* buffer; 1116 xml_extra_buffer* next; 1117 }; 1118 448 1119 struct xml_document_struct: public xml_node_struct, public xml_allocator 449 1120 { 450 xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0) 1121 xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0) 451 1122 { 452 1123 } 453 1124 454 1125 const char_t* buffer; 1126 1127 xml_extra_buffer* extra_buffers; 1128 1129 #ifdef PUGIXML_COMPACT 1130 compact_hash_table hash; 1131 #endif 455 1132 }; 456 1133 457 static inline xml_allocator& get_allocator(const xml_node_struct* node) 458 { 459 assert(node); 460 461 return *reinterpret_cast<xml_memory_page*>(node->header & xml_memory_page_pointer_mask)->allocator; 462 } 463 } 1134 template <typename Object> inline xml_allocator& get_allocator(const Object* object) 1135 { 1136 assert(object); 1137 1138 return *PUGI__GETPAGE(object)->allocator; 1139 } 1140 1141 template <typename Object> inline xml_document_struct& get_document(const Object* object) 1142 { 1143 assert(object); 1144 1145 return *static_cast<xml_document_struct*>(PUGI__GETPAGE(object)->allocator); 1146 } 1147 PUGI__NS_END 464 1148 465 1149 // Low-level DOM operations 466 namespace 467 { 1150 PUGI__NS_BEGIN 468 1151 inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc) 469 1152 { 470 1153 xml_memory_page* page; 471 void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page); 1154 void* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page); 1155 if (!memory) return 0; 472 1156 473 1157 return new (memory) xml_attribute_struct(page); … … 477 1161 { 478 1162 xml_memory_page* page; 479 void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page); 1163 void* memory = alloc.allocate_object(sizeof(xml_node_struct), page); 1164 if (!memory) return 0; 480 1165 481 1166 return new (memory) xml_node_struct(page, type); … … 484 1169 inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc) 485 1170 { 486 uintptr_t header = a->header; 487 488 if (header & xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name); 489 if (header & xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value); 490 491 alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)); 1171 if (a->header & impl::xml_memory_page_name_allocated_mask) 1172 alloc.deallocate_string(a->name); 1173 1174 if (a->header & impl::xml_memory_page_value_allocated_mask) 1175 alloc.deallocate_string(a->value); 1176 1177 alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI__GETPAGE(a)); 492 1178 } 493 1179 494 1180 inline void destroy_node(xml_node_struct* n, xml_allocator& alloc) 495 1181 { 496 uintptr_t header = n->header; 497 498 if (header & xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name); 499 if (header & xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value); 1182 if (n->header & impl::xml_memory_page_name_allocated_mask) 1183 alloc.deallocate_string(n->name); 1184 1185 if (n->header & impl::xml_memory_page_value_allocated_mask) 1186 alloc.deallocate_string(n->value); 500 1187 501 1188 for (xml_attribute_struct* attr = n->first_attribute; attr; ) … … 517 1204 } 518 1205 519 alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)); 520 } 521 522 PUGIXML_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) 523 { 1206 alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI__GETPAGE(n)); 1207 } 1208 1209 inline void append_node(xml_node_struct* child, xml_node_struct* node) 1210 { 1211 child->parent = node; 1212 1213 xml_node_struct* head = node->first_child; 1214 1215 if (head) 1216 { 1217 xml_node_struct* tail = head->prev_sibling_c; 1218 1219 tail->next_sibling = child; 1220 child->prev_sibling_c = tail; 1221 head->prev_sibling_c = child; 1222 } 1223 else 1224 { 1225 node->first_child = child; 1226 child->prev_sibling_c = child; 1227 } 1228 } 1229 1230 inline void prepend_node(xml_node_struct* child, xml_node_struct* node) 1231 { 1232 child->parent = node; 1233 1234 xml_node_struct* head = node->first_child; 1235 1236 if (head) 1237 { 1238 child->prev_sibling_c = head->prev_sibling_c; 1239 head->prev_sibling_c = child; 1240 } 1241 else 1242 child->prev_sibling_c = child; 1243 1244 child->next_sibling = head; 1245 node->first_child = child; 1246 } 1247 1248 inline void insert_node_after(xml_node_struct* child, xml_node_struct* node) 1249 { 1250 xml_node_struct* parent = node->parent; 1251 1252 child->parent = parent; 1253 1254 if (node->next_sibling) 1255 node->next_sibling->prev_sibling_c = child; 1256 else 1257 parent->first_child->prev_sibling_c = child; 1258 1259 child->next_sibling = node->next_sibling; 1260 child->prev_sibling_c = node; 1261 1262 node->next_sibling = child; 1263 } 1264 1265 inline void insert_node_before(xml_node_struct* child, xml_node_struct* node) 1266 { 1267 xml_node_struct* parent = node->parent; 1268 1269 child->parent = parent; 1270 1271 if (node->prev_sibling_c->next_sibling) 1272 node->prev_sibling_c->next_sibling = child; 1273 else 1274 parent->first_child = child; 1275 1276 child->prev_sibling_c = node->prev_sibling_c; 1277 child->next_sibling = node; 1278 1279 node->prev_sibling_c = child; 1280 } 1281 1282 inline void remove_node(xml_node_struct* node) 1283 { 1284 xml_node_struct* parent = node->parent; 1285 1286 if (node->next_sibling) 1287 node->next_sibling->prev_sibling_c = node->prev_sibling_c; 1288 else 1289 parent->first_child->prev_sibling_c = node->prev_sibling_c; 1290 1291 if (node->prev_sibling_c->next_sibling) 1292 node->prev_sibling_c->next_sibling = node->next_sibling; 1293 else 1294 parent->first_child = node->next_sibling; 1295 1296 node->parent = 0; 1297 node->prev_sibling_c = 0; 1298 node->next_sibling = 0; 1299 } 1300 1301 inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node) 1302 { 1303 xml_attribute_struct* head = node->first_attribute; 1304 1305 if (head) 1306 { 1307 xml_attribute_struct* tail = head->prev_attribute_c; 1308 1309 tail->next_attribute = attr; 1310 attr->prev_attribute_c = tail; 1311 head->prev_attribute_c = attr; 1312 } 1313 else 1314 { 1315 node->first_attribute = attr; 1316 attr->prev_attribute_c = attr; 1317 } 1318 } 1319 1320 inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node) 1321 { 1322 xml_attribute_struct* head = node->first_attribute; 1323 1324 if (head) 1325 { 1326 attr->prev_attribute_c = head->prev_attribute_c; 1327 head->prev_attribute_c = attr; 1328 } 1329 else 1330 attr->prev_attribute_c = attr; 1331 1332 attr->next_attribute = head; 1333 node->first_attribute = attr; 1334 } 1335 1336 inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) 1337 { 1338 if (place->next_attribute) 1339 place->next_attribute->prev_attribute_c = attr; 1340 else 1341 node->first_attribute->prev_attribute_c = attr; 1342 1343 attr->next_attribute = place->next_attribute; 1344 attr->prev_attribute_c = place; 1345 place->next_attribute = attr; 1346 } 1347 1348 inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) 1349 { 1350 if (place->prev_attribute_c->next_attribute) 1351 place->prev_attribute_c->next_attribute = attr; 1352 else 1353 node->first_attribute = attr; 1354 1355 attr->prev_attribute_c = place->prev_attribute_c; 1356 attr->next_attribute = place; 1357 place->prev_attribute_c = attr; 1358 } 1359 1360 inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node) 1361 { 1362 if (attr->next_attribute) 1363 attr->next_attribute->prev_attribute_c = attr->prev_attribute_c; 1364 else 1365 node->first_attribute->prev_attribute_c = attr->prev_attribute_c; 1366 1367 if (attr->prev_attribute_c->next_attribute) 1368 attr->prev_attribute_c->next_attribute = attr->next_attribute; 1369 else 1370 node->first_attribute = attr->next_attribute; 1371 1372 attr->prev_attribute_c = 0; 1373 attr->next_attribute = 0; 1374 } 1375 1376 PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element) 1377 { 1378 if (!alloc.reserve()) return 0; 1379 524 1380 xml_node_struct* child = allocate_node(alloc, type); 525 1381 if (!child) return 0; 526 1382 527 child->parent = node; 528 529 xml_node_struct* first_child = node->first_child; 530 531 if (first_child) 532 { 533 xml_node_struct* last_child = first_child->prev_sibling_c; 534 535 last_child->next_sibling = child; 536 child->prev_sibling_c = last_child; 537 first_child->prev_sibling_c = child; 538 } 539 else 540 { 541 node->first_child = child; 542 child->prev_sibling_c = child; 543 } 544 1383 append_node(child, node); 1384 545 1385 return child; 546 1386 } 547 1387 548 PUGIXML_NO_INLINE xml_attribute_struct* append_attribute_ll(xml_node_struct* node, xml_allocator& alloc) 549 { 550 xml_attribute_struct* a = allocate_attribute(alloc); 551 if (!a) return 0; 552 553 xml_attribute_struct* first_attribute = node->first_attribute; 554 555 if (first_attribute) 556 { 557 xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c; 558 559 last_attribute->next_attribute = a; 560 a->prev_attribute_c = last_attribute; 561 first_attribute->prev_attribute_c = a; 562 } 563 else 564 { 565 node->first_attribute = a; 566 a->prev_attribute_c = a; 567 } 568 569 return a; 570 } 571 } 1388 PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc) 1389 { 1390 if (!alloc.reserve()) return 0; 1391 1392 xml_attribute_struct* attr = allocate_attribute(alloc); 1393 if (!attr) return 0; 1394 1395 append_attribute(attr, node); 1396 1397 return attr; 1398 } 1399 PUGI__NS_END 572 1400 573 1401 // Helper classes for code generation 574 namespace 575 { 1402 PUGI__NS_BEGIN 576 1403 struct opt_false 577 1404 { … … 583 1410 enum { value = 1 }; 584 1411 }; 585 } 1412 PUGI__NS_END 586 1413 587 1414 // Unicode utilities 588 namespace 589 { 1415 PUGI__NS_BEGIN 590 1416 inline uint16_t endian_swap(uint16_t value) 591 1417 { … … 692 1518 static value_type high(value_type result, uint32_t ch) 693 1519 { 694 uint32_t msh = (uint32_t)(ch - 0x10000) >> 10;695 uint32_t lsh = (uint32_t)(ch - 0x10000) & 0x3ff;1520 uint32_t msh = static_cast<uint32_t>(ch - 0x10000) >> 10; 1521 uint32_t lsh = static_cast<uint32_t>(ch - 0x10000) & 0x3ff; 696 1522 697 1523 result[0] = static_cast<uint16_t>(0xD800 + msh); … … 748 1574 }; 749 1575 750 template <size_t size> struct wchar_selector; 751 752 template <> struct wchar_selector<2> 753 { 754 typedef uint16_t type; 755 typedef utf16_counter counter; 756 typedef utf16_writer writer; 1576 struct latin1_writer 1577 { 1578 typedef uint8_t* value_type; 1579 1580 static value_type low(value_type result, uint32_t ch) 1581 { 1582 *result = static_cast<uint8_t>(ch > 255 ? '?' : ch); 1583 1584 return result + 1; 1585 } 1586 1587 static value_type high(value_type result, uint32_t ch) 1588 { 1589 (void)ch; 1590 1591 *result = '?'; 1592 1593 return result + 1; 1594 } 757 1595 }; 758 1596 759 template <> struct wchar_selector<4> 760 { 761 typedef uint32_t type; 762 typedef utf32_counter counter; 763 typedef utf32_writer writer; 764 }; 765 766 typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter; 767 typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer; 768 769 template <typename Traits, typename opt_swap = opt_false> struct utf_decoder 770 { 771 static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result) 1597 struct utf8_decoder 1598 { 1599 typedef uint8_t type; 1600 1601 template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits) 772 1602 { 773 1603 const uint8_t utf8_byte_mask = 0x3f; … … 787 1617 if ((reinterpret_cast<uintptr_t>(data) & 3) == 0) 788 1618 { 789 while (size >= 4 && (*reinterpret_cast<const uint32_t*>(data) & 0x80808080) == 0) 1619 // round-trip through void* to silence 'cast increases required alignment of target type' warnings 1620 while (size >= 4 && (*static_cast<const uint32_t*>(static_cast<const void*>(data)) & 0x80808080) == 0) 790 1621 { 791 1622 result = Traits::low(result, data[0]); … … 799 1630 } 800 1631 // 110xxxxx -> U+0080..U+07FF 801 else if ( (unsigned)(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)1632 else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80) 802 1633 { 803 1634 result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask)); … … 806 1637 } 807 1638 // 1110xxxx -> U+0800-U+FFFF 808 else if ( (unsigned)(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)1639 else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) 809 1640 { 810 1641 result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask)); … … 813 1644 } 814 1645 // 11110xxx -> U+10000..U+10FFFF 815 else if ( (unsigned)(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)1646 else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80) 816 1647 { 817 1648 result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask)); … … 829 1660 return result; 830 1661 } 831 832 static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result) 833 { 834 const uint16_t* end = data + size; 835 836 while (data < end) 1662 }; 1663 1664 template <typename opt_swap> struct utf16_decoder 1665 { 1666 typedef uint16_t type; 1667 1668 template <typename Traits> static inline typename Traits::value_type process(const uint16_t* data, size_t size, typename Traits::value_type result, Traits) 1669 { 1670 while (size) 837 1671 { 838 1672 uint16_t lead = opt_swap::value ? endian_swap(*data) : *data; … … 843 1677 result = Traits::low(result, lead); 844 1678 data += 1; 1679 size -= 1; 845 1680 } 846 1681 // U+E000..U+FFFF 847 else if ( (unsigned)(lead - 0xE000) < 0x2000)1682 else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000) 848 1683 { 849 1684 result = Traits::low(result, lead); 850 1685 data += 1; 1686 size -= 1; 851 1687 } 852 1688 // surrogate pair lead 853 else if ( (unsigned)(lead - 0xD800) < 0x400 && data + 1 < end)1689 else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2) 854 1690 { 855 1691 uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1]; 856 1692 857 if ( (unsigned)(next - 0xDC00) < 0x400)1693 if (static_cast<unsigned int>(next - 0xDC00) < 0x400) 858 1694 { 859 1695 result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff)); 860 1696 data += 2; 1697 size -= 2; 861 1698 } 862 1699 else 863 1700 { 864 1701 data += 1; 1702 size -= 1; 865 1703 } 866 1704 } … … 868 1706 { 869 1707 data += 1; 1708 size -= 1; 870 1709 } 871 1710 } … … 873 1712 return result; 874 1713 } 875 876 static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result) 877 { 878 const uint32_t* end = data + size; 879 880 while (data < end) 1714 }; 1715 1716 template <typename opt_swap> struct utf32_decoder 1717 { 1718 typedef uint32_t type; 1719 1720 template <typename Traits> static inline typename Traits::value_type process(const uint32_t* data, size_t size, typename Traits::value_type result, Traits) 1721 { 1722 while (size) 881 1723 { 882 1724 uint32_t lead = opt_swap::value ? endian_swap(*data) : *data; … … 887 1729 result = Traits::low(result, lead); 888 1730 data += 1; 1731 size -= 1; 889 1732 } 890 1733 // U+10000..U+10FFFF … … 893 1736 result = Traits::high(result, lead); 894 1737 data += 1; 1738 size -= 1; 895 1739 } 896 1740 } … … 900 1744 }; 901 1745 902 template <typename T> inline void convert_utf_endian_swap(T* result, const T* data, size_t length) 903 { 904 for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]); 905 } 906 907 inline void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) 908 { 909 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]))); 910 } 911 } 912 913 namespace 914 { 1746 struct latin1_decoder 1747 { 1748 typedef uint8_t type; 1749 1750 template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits) 1751 { 1752 while (size) 1753 { 1754 result = Traits::low(result, *data); 1755 data += 1; 1756 size -= 1; 1757 } 1758 1759 return result; 1760 } 1761 }; 1762 1763 template <size_t size> struct wchar_selector; 1764 1765 template <> struct wchar_selector<2> 1766 { 1767 typedef uint16_t type; 1768 typedef utf16_counter counter; 1769 typedef utf16_writer writer; 1770 typedef utf16_decoder<opt_false> decoder; 1771 }; 1772 1773 template <> struct wchar_selector<4> 1774 { 1775 typedef uint32_t type; 1776 typedef utf32_counter counter; 1777 typedef utf32_writer writer; 1778 typedef utf32_decoder<opt_false> decoder; 1779 }; 1780 1781 typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter; 1782 typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer; 1783 1784 struct wchar_decoder 1785 { 1786 typedef wchar_t type; 1787 1788 template <typename Traits> static inline typename Traits::value_type process(const wchar_t* data, size_t size, typename Traits::value_type result, Traits traits) 1789 { 1790 typedef wchar_selector<sizeof(wchar_t)>::decoder decoder; 1791 1792 return decoder::process(reinterpret_cast<const typename decoder::type*>(data), size, result, traits); 1793 } 1794 }; 1795 1796 #ifdef PUGIXML_WCHAR_MODE 1797 PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length) 1798 { 1799 for (size_t i = 0; i < length; ++i) 1800 result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i]))); 1801 } 1802 #endif 1803 PUGI__NS_END 1804 1805 PUGI__NS_BEGIN 915 1806 enum chartype_t 916 1807 { … … 925 1816 }; 926 1817 927 const unsigned char chartype_table[256] =1818 static const unsigned char chartype_table[256] = 928 1819 { 929 1820 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15 … … 954 1845 ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . 955 1846 }; 956 957 const unsigned char chartypex_table[256] =1847 1848 static const unsigned char chartypex_table[256] = 958 1849 { 959 1850 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 … … 976 1867 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 977 1868 }; 978 1869 979 1870 #ifdef PUGIXML_WCHAR_MODE 980 #define IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))1871 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct)) 981 1872 #else 982 #define IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))1873 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct)) 983 1874 #endif 984 1875 985 #define IS_CHARTYPE(c, ct)IS_CHARTYPE_IMPL(c, ct, chartype_table)986 #define IS_CHARTYPEX(c, ct)IS_CHARTYPE_IMPL(c, ct, chartypex_table)987 988 bool is_little_endian()1876 #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table) 1877 #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table) 1878 1879 PUGI__FN bool is_little_endian() 989 1880 { 990 1881 unsigned int ui = 1; … … 993 1884 } 994 1885 995 xml_encoding get_wchar_encoding()996 { 997 STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);1886 PUGI__FN xml_encoding get_wchar_encoding() 1887 { 1888 PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); 998 1889 999 1890 if (sizeof(wchar_t) == 2) 1000 1891 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; 1001 else 1892 else 1002 1893 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; 1003 1894 } 1004 1895 1005 xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) 1006 { 1896 PUGI__FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length) 1897 { 1898 #define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; } 1899 #define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; } 1900 1901 // check if we have a non-empty XML declaration 1902 if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI__IS_CHARTYPE(data[5], ct_space))) 1903 return false; 1904 1905 // scan XML declaration until the encoding field 1906 for (size_t i = 6; i + 1 < size; ++i) 1907 { 1908 // declaration can not contain ? in quoted values 1909 if (data[i] == '?') 1910 return false; 1911 1912 if (data[i] == 'e' && data[i + 1] == 'n') 1913 { 1914 size_t offset = i; 1915 1916 // encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed 1917 PUGI__SCANCHAR('e'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('c'); PUGI__SCANCHAR('o'); 1918 PUGI__SCANCHAR('d'); PUGI__SCANCHAR('i'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('g'); 1919 1920 // S? = S? 1921 PUGI__SCANCHARTYPE(ct_space); 1922 PUGI__SCANCHAR('='); 1923 PUGI__SCANCHARTYPE(ct_space); 1924 1925 // the only two valid delimiters are ' and " 1926 uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\''; 1927 1928 PUGI__SCANCHAR(delimiter); 1929 1930 size_t start = offset; 1931 1932 out_encoding = data + offset; 1933 1934 PUGI__SCANCHARTYPE(ct_symbol); 1935 1936 out_length = offset - start; 1937 1938 PUGI__SCANCHAR(delimiter); 1939 1940 return true; 1941 } 1942 } 1943 1944 return false; 1945 1946 #undef PUGI__SCANCHAR 1947 #undef PUGI__SCANCHARTYPE 1948 } 1949 1950 PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size) 1951 { 1952 // skip encoding autodetection if input buffer is too small 1953 if (size < 4) return encoding_utf8; 1954 1955 uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; 1956 1007 1957 // look for BOM in first few bytes 1008 1958 if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; … … 1017 1967 if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be; 1018 1968 if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le; 1019 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d) return encoding_utf8;1020 1969 1021 1970 // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early) … … 1023 1972 if (d0 == 0x3c && d1 == 0) return encoding_utf16_le; 1024 1973 1025 // no known BOM detected, assume utf8 1974 // no known BOM detected; parse declaration 1975 const uint8_t* enc = 0; 1976 size_t enc_length = 0; 1977 1978 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length)) 1979 { 1980 // iso-8859-1 (case-insensitive) 1981 if (enc_length == 10 1982 && (enc[0] | ' ') == 'i' && (enc[1] | ' ') == 's' && (enc[2] | ' ') == 'o' 1983 && enc[3] == '-' && enc[4] == '8' && enc[5] == '8' && enc[6] == '5' && enc[7] == '9' 1984 && enc[8] == '-' && enc[9] == '1') 1985 return encoding_latin1; 1986 1987 // latin1 (case-insensitive) 1988 if (enc_length == 6 1989 && (enc[0] | ' ') == 'l' && (enc[1] | ' ') == 'a' && (enc[2] | ' ') == 't' 1990 && (enc[3] | ' ') == 'i' && (enc[4] | ' ') == 'n' 1991 && enc[5] == '1') 1992 return encoding_latin1; 1993 } 1994 1026 1995 return encoding_utf8; 1027 1996 } 1028 1997 1029 xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)1998 PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size) 1030 1999 { 1031 2000 // replace wchar encoding with utf implementation … … 1041 2010 if (encoding != encoding_auto) return encoding; 1042 2011 1043 // skip encoding autodetection if input buffer is too small1044 if (size < 4) return encoding_utf8;1045 1046 2012 // try to guess encoding (based on XML specification, Appendix F.1) 1047 2013 const uint8_t* data = static_cast<const uint8_t*>(contents); 1048 2014 1049 DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];1050 1051 return guess_buffer_encoding(d0, d1, d2, d3); 1052 }1053 1054 bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)1055 { 2015 return guess_buffer_encoding(data, size); 2016 } 2017 2018 PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) 2019 { 2020 size_t length = size / sizeof(char_t); 2021 1056 2022 if (is_mutable) 1057 2023 { 1058 2024 out_buffer = static_cast<char_t*>(const_cast<void*>(contents)); 2025 out_length = length; 1059 2026 } 1060 2027 else 1061 2028 { 1062 void* buffer = global_allocate(size > 0 ? size : 1);2029 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t))); 1063 2030 if (!buffer) return false; 1064 2031 1065 memcpy(buffer, contents, size); 1066 1067 out_buffer = static_cast<char_t*>(buffer); 1068 } 1069 1070 out_length = size / sizeof(char_t); 2032 if (contents) 2033 memcpy(buffer, contents, length * sizeof(char_t)); 2034 else 2035 assert(length == 0); 2036 2037 buffer[length] = 0; 2038 2039 out_buffer = buffer; 2040 out_length = length + 1; 2041 } 1071 2042 1072 2043 return true; … … 1074 2045 1075 2046 #ifdef PUGIXML_WCHAR_MODE 1076 inlinebool need_endian_swap_utf(xml_encoding le, xml_encoding re)2047 PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re) 1077 2048 { 1078 2049 return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) || 1079 1080 } 1081 1082 bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)2050 (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be); 2051 } 2052 2053 PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) 1083 2054 { 1084 2055 const char_t* data = static_cast<const char_t*>(contents); 1085 2056 size_t length = size / sizeof(char_t); 2057 1086 2058 if (is_mutable) 1087 2059 { 1088 out_buffer = const_cast<char_t*>(data); 2060 char_t* buffer = const_cast<char_t*>(data); 2061 2062 convert_wchar_endian_swap(buffer, data, length); 2063 2064 out_buffer = buffer; 2065 out_length = length; 1089 2066 } 1090 2067 else 1091 2068 { 1092 out_buffer = static_cast<char_t*>(global_allocate(size > 0 ? size : 1)); 1093 if (!out_buffer) return false; 1094 } 1095 1096 out_length = size / sizeof(char_t); 1097 1098 convert_wchar_endian_swap(out_buffer, data, out_length); 2069 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t))); 2070 if (!buffer) return false; 2071 2072 convert_wchar_endian_swap(buffer, data, length); 2073 buffer[length] = 0; 2074 2075 out_buffer = buffer; 2076 out_length = length + 1; 2077 } 1099 2078 1100 2079 return true; 1101 2080 } 1102 2081 1103 bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size) 1104 { 1105 const uint8_t* data = static_cast<const uint8_t*>(contents); 2082 template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) 2083 { 2084 const typename D::type* data = static_cast<const typename D::type*>(contents); 2085 size_t data_length = size / sizeof(typename D::type); 1106 2086 1107 2087 // first pass: get length in wchar_t units 1108 out_length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);2088 size_t length = D::process(data, data_length, 0, wchar_counter()); 1109 2089 1110 2090 // allocate buffer of suitable length 1111 out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); 1112 if (!out_buffer) return false; 1113 1114 // second pass: convert utf8 input to wchar_t 1115 wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer); 1116 wchar_writer::value_type out_end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, out_begin); 1117 1118 assert(out_end == out_begin + out_length); 1119 (void)!out_end; 2091 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t))); 2092 if (!buffer) return false; 2093 2094 // second pass: convert utf16 input to wchar_t 2095 wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer); 2096 wchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer()); 2097 2098 assert(oend == obegin + length); 2099 *oend = 0; 2100 2101 out_buffer = buffer; 2102 out_length = length + 1; 1120 2103 1121 2104 return true; 1122 2105 } 1123 2106 1124 template <typename opt_swap> bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) 1125 { 1126 const uint16_t* data = static_cast<const uint16_t*>(contents); 1127 size_t length = size / sizeof(uint16_t); 1128 1129 // first pass: get length in wchar_t units 1130 out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf16_block(data, length, 0); 1131 1132 // allocate buffer of suitable length 1133 out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); 1134 if (!out_buffer) return false; 1135 1136 // second pass: convert utf16 input to wchar_t 1137 wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer); 1138 wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf16_block(data, length, out_begin); 1139 1140 assert(out_end == out_begin + out_length); 1141 (void)!out_end; 1142 1143 return true; 1144 } 1145 1146 template <typename opt_swap> bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) 1147 { 1148 const uint32_t* data = static_cast<const uint32_t*>(contents); 1149 size_t length = size / sizeof(uint32_t); 1150 1151 // first pass: get length in wchar_t units 1152 out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf32_block(data, length, 0); 1153 1154 // allocate buffer of suitable length 1155 out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); 1156 if (!out_buffer) return false; 1157 1158 // second pass: convert utf32 input to wchar_t 1159 wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer); 1160 wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf32_block(data, length, out_begin); 1161 1162 assert(out_end == out_begin + out_length); 1163 (void)!out_end; 1164 1165 return true; 1166 } 1167 1168 bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable) 2107 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) 1169 2108 { 1170 2109 // get native encoding … … 1172 2111 1173 2112 // fast path: no conversion required 1174 if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); 2113 if (encoding == wchar_encoding) 2114 return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); 1175 2115 1176 2116 // only endian-swapping is required 1177 if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); 2117 if (need_endian_swap_utf(encoding, wchar_encoding)) 2118 return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable); 1178 2119 1179 2120 // source encoding is utf8 1180 if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size); 2121 if (encoding == encoding_utf8) 2122 return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder()); 1181 2123 1182 2124 // source encoding is utf16 … … 1186 2128 1187 2129 return (native_encoding == encoding) ? 1188 convert_buffer_ utf16(out_buffer, out_length, contents, size, opt_false()) :1189 convert_buffer_ utf16(out_buffer, out_length, contents, size, opt_true());2130 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) : 2131 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>()); 1190 2132 } 1191 2133 … … 1196 2138 1197 2139 return (native_encoding == encoding) ? 1198 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : 1199 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); 1200 } 1201 1202 assert(!"Invalid encoding"); 2140 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) : 2141 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>()); 2142 } 2143 2144 // source encoding is latin1 2145 if (encoding == encoding_latin1) 2146 return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder()); 2147 2148 assert(false && "Invalid encoding"); 1203 2149 return false; 1204 2150 } 1205 2151 #else 1206 template <typename opt_swap> bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)1207 { 1208 const uint16_t* data = static_cast<const uint16_t*>(contents);1209 size_t length = size / sizeof(uint16_t);2152 template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) 2153 { 2154 const typename D::type* data = static_cast<const typename D::type*>(contents); 2155 size_t data_length = size / sizeof(typename D::type); 1210 2156 1211 2157 // first pass: get length in utf8 units 1212 out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf16_block(data, length, 0);2158 size_t length = D::process(data, data_length, 0, utf8_counter()); 1213 2159 1214 2160 // allocate buffer of suitable length 1215 out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length :1) * sizeof(char_t)));1216 if (! out_buffer) return false;2161 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t))); 2162 if (!buffer) return false; 1217 2163 1218 2164 // second pass: convert utf16 input to utf8 1219 uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer); 1220 uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf16_block(data, length, out_begin); 1221 1222 assert(out_end == out_begin + out_length); 1223 (void)!out_end; 2165 uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer); 2166 uint8_t* oend = D::process(data, data_length, obegin, utf8_writer()); 2167 2168 assert(oend == obegin + length); 2169 *oend = 0; 2170 2171 out_buffer = buffer; 2172 out_length = length + 1; 1224 2173 1225 2174 return true; 1226 2175 } 1227 2176 1228 template <typename opt_swap> bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap) 1229 { 1230 const uint32_t* data = static_cast<const uint32_t*>(contents); 1231 size_t length = size / sizeof(uint32_t); 2177 PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size) 2178 { 2179 for (size_t i = 0; i < size; ++i) 2180 if (data[i] > 127) 2181 return i; 2182 2183 return size; 2184 } 2185 2186 PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) 2187 { 2188 const uint8_t* data = static_cast<const uint8_t*>(contents); 2189 size_t data_length = size; 2190 2191 // get size of prefix that does not need utf8 conversion 2192 size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length); 2193 assert(prefix_length <= data_length); 2194 2195 const uint8_t* postfix = data + prefix_length; 2196 size_t postfix_length = data_length - prefix_length; 2197 2198 // if no conversion is needed, just return the original buffer 2199 if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); 1232 2200 1233 2201 // first pass: get length in utf8 units 1234 out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf32_block(data, length, 0);2202 size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter()); 1235 2203 1236 2204 // allocate buffer of suitable length 1237 out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t))); 1238 if (!out_buffer) return false; 1239 1240 // second pass: convert utf32 input to utf8 1241 uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer); 1242 uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf32_block(data, length, out_begin); 1243 1244 assert(out_end == out_begin + out_length); 1245 (void)!out_end; 2205 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t))); 2206 if (!buffer) return false; 2207 2208 // second pass: convert latin1 input to utf8 2209 memcpy(buffer, data, prefix_length); 2210 2211 uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer); 2212 uint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer()); 2213 2214 assert(oend == obegin + length); 2215 *oend = 0; 2216 2217 out_buffer = buffer; 2218 out_length = length + 1; 1246 2219 1247 2220 return true; 1248 2221 } 1249 2222 1250 bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)2223 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) 1251 2224 { 1252 2225 // fast path: no conversion required 1253 if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); 2226 if (encoding == encoding_utf8) 2227 return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable); 1254 2228 1255 2229 // source encoding is utf16 … … 1259 2233 1260 2234 return (native_encoding == encoding) ? 1261 convert_buffer_ utf16(out_buffer, out_length, contents, size, opt_false()) :1262 convert_buffer_ utf16(out_buffer, out_length, contents, size, opt_true());2235 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) : 2236 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>()); 1263 2237 } 1264 2238 … … 1269 2243 1270 2244 return (native_encoding == encoding) ? 1271 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) : 1272 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true()); 1273 } 1274 1275 assert(!"Invalid encoding"); 2245 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) : 2246 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>()); 2247 } 2248 2249 // source encoding is latin1 2250 if (encoding == encoding_latin1) 2251 return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); 2252 2253 assert(false && "Invalid encoding"); 1276 2254 return false; 1277 2255 } 1278 2256 #endif 1279 2257 1280 size_t as_utf8_begin(const wchar_t* str, size_t length) 1281 { 1282 STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); 1283 2258 PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length) 2259 { 1284 2260 // get length in utf8 characters 1285 return sizeof(wchar_t) == 2 ? 1286 utf_decoder<utf8_counter>::decode_utf16_block(reinterpret_cast<const uint16_t*>(str), length, 0) : 1287 utf_decoder<utf8_counter>::decode_utf32_block(reinterpret_cast<const uint32_t*>(str), length, 0); 1288 } 1289 1290 void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) 1291 { 1292 STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); 1293 1294 // convert to utf8 1295 uint8_t* begin = reinterpret_cast<uint8_t*>(buffer); 1296 uint8_t* end = sizeof(wchar_t) == 2 ? 1297 utf_decoder<utf8_writer>::decode_utf16_block(reinterpret_cast<const uint16_t*>(str), length, begin) : 1298 utf_decoder<utf8_writer>::decode_utf32_block(reinterpret_cast<const uint32_t*>(str), length, begin); 1299 1300 assert(begin + size == end); 1301 (void)!end; 1302 1303 // zero-terminate 1304 buffer[size] = 0; 1305 } 1306 2261 return wchar_decoder::process(str, length, 0, utf8_counter()); 2262 } 2263 2264 PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) 2265 { 2266 // convert to utf8 2267 uint8_t* begin = reinterpret_cast<uint8_t*>(buffer); 2268 uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer()); 2269 2270 assert(begin + size == end); 2271 (void)!end; 2272 (void)!size; 2273 } 2274 1307 2275 #ifndef PUGIXML_NO_STL 1308 1309 2276 PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) 2277 { 1310 2278 // first pass: get length in utf8 characters 1311 2279 size_t size = as_utf8_begin(str, length); 1312 2280 1313 2281 // allocate resulting string … … 1318 2286 if (size > 0) as_utf8_end(&result[0], size, str, length); 1319 2287 1320 1321 1322 1323 std::wstringas_wide_impl(const char* str, size_t size)2288 return result; 2289 } 2290 2291 PUGI__FN std::basic_string<wchar_t> as_wide_impl(const char* str, size_t size) 1324 2292 { 1325 2293 const uint8_t* data = reinterpret_cast<const uint8_t*>(str); 1326 2294 1327 2295 // first pass: get length in wchar_t units 1328 size_t length = utf _decoder<wchar_counter>::decode_utf8_block(data, size, 0);2296 size_t length = utf8_decoder::process(data, size, 0, wchar_counter()); 1329 2297 1330 2298 // allocate resulting string 1331 std:: wstringresult;2299 std::basic_string<wchar_t> result; 1332 2300 result.resize(length); 1333 2301 … … 1336 2304 { 1337 2305 wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]); 1338 wchar_writer::value_type end = utf _decoder<wchar_writer>::decode_utf8_block(data, size, begin);2306 wchar_writer::value_type end = utf8_decoder::process(data, size, begin, wchar_writer()); 1339 2307 1340 2308 assert(begin + length == end); … … 1346 2314 #endif 1347 2315 1348 inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target) 1349 { 1350 assert(target); 2316 template <typename Header> 2317 inline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target) 2318 { 2319 // never reuse shared memory 2320 if (header & xml_memory_page_contents_shared_mask) return false; 2321 1351 2322 size_t target_length = strlength(target); 1352 2323 1353 2324 // always reuse document buffer memory if possible 1354 if ( !allocated) return target_length >= length;2325 if ((header & header_mask) == 0) return target_length >= length; 1355 2326 1356 2327 // reuse heap memory if waste is not too great … … 1360 2331 } 1361 2332 1362 bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source) 1363 { 1364 size_t source_length = strlength(source); 1365 2333 template <typename String, typename Header> 2334 PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length) 2335 { 1366 2336 if (source_length == 0) 1367 2337 { 1368 2338 // empty string and null pointer are equivalent, so just deallocate old memory 1369 xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator;2339 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; 1370 2340 1371 2341 if (header & header_mask) alloc->deallocate_string(dest); 1372 2342 1373 2343 // mark the string as not allocated 1374 2344 dest = 0; … … 1377 2347 return true; 1378 2348 } 1379 else if (dest && strcpy_insitu_allow(source_length, header &header_mask, dest))2349 else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) 1380 2350 { 1381 2351 // we can reuse old buffer, so just copy the new data (including zero terminator) 1382 memcpy(dest, source, (source_length + 1) * sizeof(char_t)); 1383 2352 memcpy(dest, source, source_length * sizeof(char_t)); 2353 dest[source_length] = 0; 2354 1384 2355 return true; 1385 2356 } 1386 2357 else 1387 2358 { 1388 xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator; 2359 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; 2360 2361 if (!alloc->reserve()) return false; 1389 2362 1390 2363 // allocate new buffer … … 1393 2366 1394 2367 // copy the string (including zero terminator) 1395 memcpy(buf, source, (source_length + 1) * sizeof(char_t)); 2368 memcpy(buf, source, source_length * sizeof(char_t)); 2369 buf[source_length] = 0; 1396 2370 1397 2371 // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) 1398 2372 if (header & header_mask) alloc->deallocate_string(dest); 1399 2373 1400 2374 // the string is now allocated, so set the flag 1401 2375 dest = buf; … … 1410 2384 char_t* end; 1411 2385 size_t size; 1412 2386 1413 2387 gap(): end(0), size(0) 1414 2388 { 1415 2389 } 1416 2390 1417 2391 // Push new gap, move s count bytes further (skipping the gap). 1418 2392 // Collapse previous gap. … … 1425 2399 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end)); 1426 2400 } 1427 2401 1428 2402 s += count; // end of current gap 1429 2403 1430 2404 // "merge" two gaps 1431 2405 end = s; 1432 2406 size += count; 1433 2407 } 1434 2408 1435 2409 // Collapse all gaps, return past-the-end pointer 1436 2410 char_t* flush(char_t* s) … … 1447 2421 } 1448 2422 }; 1449 1450 char_t* strconv_escape(char_t* s, gap& g)2423 2424 PUGI__FN char_t* strconv_escape(char_t* s, gap& g) 1451 2425 { 1452 2426 char_t* stre = s + 1; … … 1479 2453 ch = *++stre; 1480 2454 } 1481 2455 1482 2456 ++stre; 1483 2457 } … … 1490 2464 for (;;) 1491 2465 { 1492 if (static_cast<unsigned int>( ch- '0') <= 9)2466 if (static_cast<unsigned int>(static_cast<unsigned int>(ch) - '0') <= 9) 1493 2467 ucsc = 10 * ucsc + (ch - '0'); 1494 2468 else if (ch == ';') … … 1499 2473 ch = *++stre; 1500 2474 } 1501 2475 1502 2476 ++stre; 1503 2477 } … … 1508 2482 s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc)); 1509 2483 #endif 1510 2484 1511 2485 g.push(s, stre - s); 1512 2486 return stre; 1513 2487 } 2488 1514 2489 case 'a': // &a 1515 2490 { … … 1522 2497 *s++ = '&'; 1523 2498 ++stre; 1524 2499 1525 2500 g.push(s, stre - s); 1526 2501 return stre; … … 1540 2515 break; 1541 2516 } 2517 1542 2518 case 'g': // &g 1543 2519 { … … 1546 2522 *s++ = '>'; 1547 2523 ++stre; 1548 2524 1549 2525 g.push(s, stre - s); 1550 2526 return stre; … … 1552 2528 break; 1553 2529 } 2530 1554 2531 case 'l': // &l 1555 2532 { … … 1558 2535 *s++ = '<'; 1559 2536 ++stre; 1560 2537 1561 2538 g.push(s, stre - s); 1562 2539 return stre; … … 1564 2541 break; 1565 2542 } 2543 1566 2544 case 'q': // &q 1567 2545 { … … 1570 2548 *s++ = '"'; 1571 2549 ++stre; 1572 2550 1573 2551 g.push(s, stre - s); 1574 2552 return stre; … … 1576 2554 break; 1577 2555 } 1578 } 1579 2556 2557 default: 2558 break; 2559 } 2560 1580 2561 return stre; 1581 2562 } 1582 2563 1583 // Utility macro for last character handling 1584 #define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) 1585 1586 char_t* strconv_comment(char_t* s, char_t endch) 2564 // Parser utilities 2565 #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) 2566 #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } 2567 #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) 2568 #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } 2569 #define PUGI__POPNODE() { cursor = cursor->parent; } 2570 #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } 2571 #define PUGI__SCANWHILE(X) { while (X) ++s; } 2572 #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } } 2573 #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } 2574 #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast<char_t*>(0) 2575 #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } 2576 2577 PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) 1587 2578 { 1588 2579 gap g; 1589 2580 1590 2581 while (true) 1591 2582 { 1592 while (!IS_CHARTYPE(*s, ct_parse_comment)) ++s;1593 2583 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); 2584 1594 2585 if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair 1595 2586 { 1596 2587 *s++ = '\n'; // replace first one with 0x0a 1597 2588 1598 2589 if (*s == '\n') g.push(s, 1); 1599 2590 } 1600 else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here2591 else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here 1601 2592 { 1602 2593 *g.flush(s) = 0; 1603 2594 1604 2595 return s + (s[2] == '>' ? 3 : 2); 1605 2596 } … … 1612 2603 } 1613 2604 1614 char_t* strconv_cdata(char_t* s, char_t endch)2605 PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) 1615 2606 { 1616 2607 gap g; 1617 2608 1618 2609 while (true) 1619 2610 { 1620 while (!IS_CHARTYPE(*s, ct_parse_cdata)) ++s;1621 2611 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); 2612 1622 2613 if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair 1623 2614 { 1624 2615 *s++ = '\n'; // replace first one with 0x0a 1625 2616 1626 2617 if (*s == '\n') g.push(s, 1); 1627 2618 } 1628 else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here2619 else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here 1629 2620 { 1630 2621 *g.flush(s) = 0; 1631 2622 1632 2623 return s + 1; 1633 2624 } … … 1639 2630 } 1640 2631 } 1641 2632 1642 2633 typedef char_t* (*strconv_pcdata_t)(char_t*); 1643 1644 template <typename opt_ eol, typename opt_escape> struct strconv_pcdata_impl2634 2635 template <typename opt_trim, typename opt_eol, typename opt_escape> struct strconv_pcdata_impl 1645 2636 { 1646 2637 static char_t* parse(char_t* s) 1647 2638 { 1648 2639 gap g; 1649 2640 2641 char_t* begin = s; 2642 1650 2643 while (true) 1651 2644 { 1652 while (!IS_CHARTYPE(*s, ct_parse_pcdata)) ++s;1653 2645 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_pcdata)); 2646 1654 2647 if (*s == '<') // PCDATA ends here 1655 2648 { 1656 *g.flush(s) = 0; 1657 2649 char_t* end = g.flush(s); 2650 2651 if (opt_trim::value) 2652 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) 2653 --end; 2654 2655 *end = 0; 2656 1658 2657 return s + 1; 1659 2658 } … … 1661 2660 { 1662 2661 *s++ = '\n'; // replace first one with 0x0a 1663 2662 1664 2663 if (*s == '\n') g.push(s, 1); 1665 2664 } … … 1670 2669 else if (*s == 0) 1671 2670 { 2671 char_t* end = g.flush(s); 2672 2673 if (opt_trim::value) 2674 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) 2675 --end; 2676 2677 *end = 0; 2678 1672 2679 return s; 1673 2680 } … … 1676 2683 } 1677 2684 }; 1678 1679 strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) 1680 { 1681 STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20); 1682 1683 switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes) 1684 { 1685 case 0: return strconv_pcdata_impl<opt_false, opt_false>::parse; 1686 case 1: return strconv_pcdata_impl<opt_false, opt_true>::parse; 1687 case 2: return strconv_pcdata_impl<opt_true, opt_false>::parse; 1688 case 3: return strconv_pcdata_impl<opt_true, opt_true>::parse; 1689 default: return 0; // should not get here 2685 2686 PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) 2687 { 2688 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); 2689 2690 switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (eol escapes trim) 2691 { 2692 case 0: return strconv_pcdata_impl<opt_false, opt_false, opt_false>::parse; 2693 case 1: return strconv_pcdata_impl<opt_false, opt_false, opt_true>::parse; 2694 case 2: return strconv_pcdata_impl<opt_false, opt_true, opt_false>::parse; 2695 case 3: return strconv_pcdata_impl<opt_false, opt_true, opt_true>::parse; 2696 case 4: return strconv_pcdata_impl<opt_true, opt_false, opt_false>::parse; 2697 case 5: return strconv_pcdata_impl<opt_true, opt_false, opt_true>::parse; 2698 case 6: return strconv_pcdata_impl<opt_true, opt_true, opt_false>::parse; 2699 case 7: return strconv_pcdata_impl<opt_true, opt_true, opt_true>::parse; 2700 default: assert(false); return 0; // should not get here 1690 2701 } 1691 2702 } 1692 2703 1693 2704 typedef char_t* (*strconv_attribute_t)(char_t*, char_t); 1694 2705 1695 2706 template <typename opt_escape> struct strconv_attribute_impl 1696 2707 { … … 1700 2711 1701 2712 // trim leading whitespaces 1702 if ( IS_CHARTYPE(*s, ct_space))2713 if (PUGI__IS_CHARTYPE(*s, ct_space)) 1703 2714 { 1704 2715 char_t* str = s; 1705 2716 1706 2717 do ++str; 1707 while ( IS_CHARTYPE(*str, ct_space));1708 2718 while (PUGI__IS_CHARTYPE(*str, ct_space)); 2719 1709 2720 g.push(s, str - s); 1710 2721 } … … 1712 2723 while (true) 1713 2724 { 1714 while (!IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) ++s;1715 2725 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); 2726 1716 2727 if (*s == end_quote) 1717 2728 { 1718 2729 char_t* str = g.flush(s); 1719 2730 1720 2731 do *str-- = 0; 1721 while ( IS_CHARTYPE(*str, ct_space));1722 2732 while (PUGI__IS_CHARTYPE(*str, ct_space)); 2733 1723 2734 return s + 1; 1724 2735 } 1725 else if ( IS_CHARTYPE(*s, ct_space))2736 else if (PUGI__IS_CHARTYPE(*s, ct_space)) 1726 2737 { 1727 2738 *s++ = ' '; 1728 1729 if ( IS_CHARTYPE(*s, ct_space))2739 2740 if (PUGI__IS_CHARTYPE(*s, ct_space)) 1730 2741 { 1731 2742 char_t* str = s + 1; 1732 while ( IS_CHARTYPE(*str, ct_space)) ++str;1733 2743 while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; 2744 1734 2745 g.push(s, str - s); 1735 2746 } … … 1753 2764 while (true) 1754 2765 { 1755 while (!IS_CHARTYPE(*s, ct_parse_attr_ws)) ++s;1756 2766 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); 2767 1757 2768 if (*s == end_quote) 1758 2769 { 1759 2770 *g.flush(s) = 0; 1760 2771 1761 2772 return s + 1; 1762 2773 } 1763 else if ( IS_CHARTYPE(*s, ct_space))2774 else if (PUGI__IS_CHARTYPE(*s, ct_space)) 1764 2775 { 1765 2776 if (*s == '\r') 1766 2777 { 1767 2778 *s++ = ' '; 1768 2779 1769 2780 if (*s == '\n') g.push(s, 1); 1770 2781 } … … 1789 2800 while (true) 1790 2801 { 1791 while (!IS_CHARTYPE(*s, ct_parse_attr)) ++s;1792 2802 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); 2803 1793 2804 if (*s == end_quote) 1794 2805 { 1795 2806 *g.flush(s) = 0; 1796 2807 1797 2808 return s + 1; 1798 2809 } … … 1800 2811 { 1801 2812 *s++ = '\n'; 1802 2813 1803 2814 if (*s == '\n') g.push(s, 1); 1804 2815 } … … 1821 2832 while (true) 1822 2833 { 1823 while (!IS_CHARTYPE(*s, ct_parse_attr)) ++s;1824 2834 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); 2835 1825 2836 if (*s == end_quote) 1826 2837 { 1827 2838 *g.flush(s) = 0; 1828 2839 1829 2840 return s + 1; 1830 2841 } … … 1842 2853 }; 1843 2854 1844 strconv_attribute_t get_strconv_attribute(unsigned int optmask)1845 { 1846 STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);1847 2855 PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) 2856 { 2857 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); 2858 1848 2859 switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) 1849 2860 { … … 1864 2875 case 14: return strconv_attribute_impl<opt_false>::parse_wnorm; 1865 2876 case 15: return strconv_attribute_impl<opt_true>::parse_wnorm; 1866 default: return 0; // should not get here2877 default: assert(false); return 0; // should not get here 1867 2878 } 1868 2879 } … … 1879 2890 struct xml_parser 1880 2891 { 1881 xml_allocator alloc;2892 xml_allocator* alloc; 1882 2893 char_t* error_offset; 1883 jmp_buf error_handler; 1884 1885 // Parser utilities. 1886 #define SKIPWS() { while (IS_CHARTYPE(*s, ct_space)) ++s; } 1887 #define OPTSET(OPT) ( optmsk & OPT ) 1888 #define PUSHNODE(TYPE) { cursor = append_node(cursor, alloc, TYPE); if (!cursor) THROW_ERROR(status_out_of_memory, s); } 1889 #define POPNODE() { cursor = cursor->parent; } 1890 #define SCANFOR(X) { while (*s != 0 && !(X)) ++s; } 1891 #define SCANWHILE(X) { while ((X)) ++s; } 1892 #define ENDSEG() { ch = *s; *s = 0; ++s; } 1893 #define THROW_ERROR(err, m) error_offset = m, longjmp(error_handler, err) 1894 #define CHECK_ERROR(err, m) { if (*s == 0) THROW_ERROR(err, m); } 1895 1896 xml_parser(const xml_allocator& alloc): alloc(alloc), error_offset(0) 2894 xml_parse_status error_status; 2895 2896 xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(0), error_status(status_ok) 1897 2897 { 1898 2898 } … … 1911 2911 // quoted string 1912 2912 char_t ch = *s++; 1913 SCANFOR(*s == ch);1914 if (!*s) THROW_ERROR(status_bad_doctype, s);2913 PUGI__SCANFOR(*s == ch); 2914 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); 1915 2915 1916 2916 s++; … … 1920 2920 // <? ... ?> 1921 2921 s += 2; 1922 SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype1923 if (!*s) THROW_ERROR(status_bad_doctype, s);2922 PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype 2923 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); 1924 2924 1925 2925 s += 2; … … 1928 2928 { 1929 2929 s += 4; 1930 SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype1931 if (!*s) THROW_ERROR(status_bad_doctype, s);1932 1933 s += 4;1934 } 1935 else THROW_ERROR(status_bad_doctype, s);2930 PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype 2931 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s); 2932 2933 s += 3; 2934 } 2935 else PUGI__THROW_ERROR(status_bad_doctype, s); 1936 2936 1937 2937 return s; … … 1940 2940 char_t* parse_doctype_ignore(char_t* s) 1941 2941 { 2942 size_t depth = 0; 2943 1942 2944 assert(s[0] == '<' && s[1] == '!' && s[2] == '['); 1943 s ++;2945 s += 3; 1944 2946 1945 2947 while (*s) … … 1948 2950 { 1949 2951 // nested ignore section 1950 s = parse_doctype_ignore(s); 2952 s += 3; 2953 depth++; 1951 2954 } 1952 2955 else if (s[0] == ']' && s[1] == ']' && s[2] == '>') … … 1955 2958 s += 3; 1956 2959 1957 return s; 2960 if (depth == 0) 2961 return s; 2962 2963 depth--; 1958 2964 } 1959 2965 else s++; 1960 2966 } 1961 2967 1962 THROW_ERROR(status_bad_doctype, s);1963 1964 return s; 1965 }1966 1967 char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel)1968 { 1969 assert( s[0] == '<'&& s[1] == '!');1970 s ++;2968 PUGI__THROW_ERROR(status_bad_doctype, s); 2969 } 2970 2971 char_t* parse_doctype_group(char_t* s, char_t endch) 2972 { 2973 size_t depth = 0; 2974 2975 assert((s[0] == '<' || s[0] == 0) && s[1] == '!'); 2976 s += 2; 1971 2977 1972 2978 while (*s) … … 1978 2984 // ignore 1979 2985 s = parse_doctype_ignore(s); 2986 if (!s) return s; 1980 2987 } 1981 2988 else 1982 2989 { 1983 2990 // some control group 1984 s = parse_doctype_group(s, endch, false); 2991 s += 2; 2992 depth++; 1985 2993 } 1986 2994 } … … 1989 2997 // unknown tag (forbidden), or some primitive group 1990 2998 s = parse_doctype_primitive(s); 2999 if (!s) return s; 1991 3000 } 1992 3001 else if (*s == '>') 1993 3002 { 3003 if (depth == 0) 3004 return s; 3005 3006 depth--; 1994 3007 s++; 1995 1996 return s;1997 3008 } 1998 3009 else s++; 1999 3010 } 2000 3011 2001 if ( !toplevel || endch != '>')THROW_ERROR(status_bad_doctype, s);3012 if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s); 2002 3013 2003 3014 return s; … … 2017 3028 ++s; 2018 3029 2019 if ( OPTSET(parse_comments))3030 if (PUGI__OPTSET(parse_comments)) 2020 3031 { 2021 PU SHNODE(node_comment); // Append a new node on the tree.3032 PUGI__PUSHNODE(node_comment); // Append a new node on the tree. 2022 3033 cursor->value = s; // Save the offset. 2023 3034 } 2024 3035 2025 if ( OPTSET(parse_eol) &&OPTSET(parse_comments))3036 if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments)) 2026 3037 { 2027 3038 s = strconv_comment(s, endch); 2028 3039 2029 if (!s) THROW_ERROR(status_bad_comment, cursor->value);3040 if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value); 2030 3041 } 2031 3042 else 2032 3043 { 2033 3044 // Scan for terminating '-->'. 2034 SCANFOR(s[0] == '-' && s[1] == '-' &&ENDSWITH(s[2], '>'));2035 CHECK_ERROR(status_bad_comment, s);2036 2037 if ( OPTSET(parse_comments))3045 PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')); 3046 PUGI__CHECK_ERROR(status_bad_comment, s); 3047 3048 if (PUGI__OPTSET(parse_comments)) 2038 3049 *s = 0; // Zero-terminate this segment at the first terminating '-'. 2039 3050 … … 2041 3052 } 2042 3053 } 2043 else THROW_ERROR(status_bad_comment, s);3054 else PUGI__THROW_ERROR(status_bad_comment, s); 2044 3055 } 2045 3056 else if (*s == '[') … … 2050 3061 ++s; 2051 3062 2052 if ( OPTSET(parse_cdata))3063 if (PUGI__OPTSET(parse_cdata)) 2053 3064 { 2054 PU SHNODE(node_cdata); // Append a new node on the tree.3065 PUGI__PUSHNODE(node_cdata); // Append a new node on the tree. 2055 3066 cursor->value = s; // Save the offset. 2056 3067 2057 if ( OPTSET(parse_eol))3068 if (PUGI__OPTSET(parse_eol)) 2058 3069 { 2059 3070 s = strconv_cdata(s, endch); 2060 3071 2061 if (!s) THROW_ERROR(status_bad_cdata, cursor->value);3072 if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value); 2062 3073 } 2063 3074 else 2064 3075 { 2065 3076 // Scan for terminating ']]>'. 2066 SCANFOR(s[0] == ']' && s[1] == ']' &&ENDSWITH(s[2], '>'));2067 CHECK_ERROR(status_bad_cdata, s);3077 PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); 3078 PUGI__CHECK_ERROR(status_bad_cdata, s); 2068 3079 2069 3080 *s++ = 0; // Zero-terminate this segment. … … 2073 3084 { 2074 3085 // Scan for terminating ']]>'. 2075 SCANFOR(s[0] == ']' && s[1] == ']' &&ENDSWITH(s[2], '>'));2076 CHECK_ERROR(status_bad_cdata, s);3086 PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); 3087 PUGI__CHECK_ERROR(status_bad_cdata, s); 2077 3088 2078 3089 ++s; … … 2081 3092 s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'. 2082 3093 } 2083 else THROW_ERROR(status_bad_cdata, s);2084 } 2085 else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E'))3094 else PUGI__THROW_ERROR(status_bad_cdata, s); 3095 } 3096 else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI__ENDSWITH(s[6], 'E')) 2086 3097 { 2087 3098 s -= 2; 2088 3099 2089 if (cursor->parent) THROW_ERROR(status_bad_doctype, s); 2090 2091 char_t* mark = s + 9; 2092 2093 s = parse_doctype_group(s, endch, true); 2094 2095 if (OPTSET(parse_doctype)) 2096 { 2097 while (IS_CHARTYPE(*mark, ct_space)) ++mark; 2098 2099 PUSHNODE(node_doctype); 2100 2101 cursor->value = mark; 2102 2103 assert((s[0] == 0 && endch == '>') || s[-1] == '>'); 2104 s[*s == 0 ? 0 : -1] = 0; 2105 2106 POPNODE(); 2107 } 2108 } 2109 else if (*s == 0 && endch == '-') THROW_ERROR(status_bad_comment, s); 2110 else if (*s == 0 && endch == '[') THROW_ERROR(status_bad_cdata, s); 2111 else THROW_ERROR(status_unrecognized_tag, s); 3100 if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s); 3101 3102 char_t* mark = s + 9; 3103 3104 s = parse_doctype_group(s, endch); 3105 if (!s) return s; 3106 3107 assert((*s == 0 && endch == '>') || *s == '>'); 3108 if (*s) *s++ = 0; 3109 3110 if (PUGI__OPTSET(parse_doctype)) 3111 { 3112 while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark; 3113 3114 PUGI__PUSHNODE(node_doctype); 3115 3116 cursor->value = mark; 3117 } 3118 } 3119 else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s); 3120 else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s); 3121 else PUGI__THROW_ERROR(status_unrecognized_tag, s); 2112 3122 2113 3123 return s; … … 2126 3136 char_t* target = s; 2127 3137 2128 if (! IS_CHARTYPE(*s, ct_start_symbol))THROW_ERROR(status_bad_pi, s);2129 2130 SCANWHILE(IS_CHARTYPE(*s, ct_symbol));2131 CHECK_ERROR(status_bad_pi, s);3138 if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s); 3139 3140 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); 3141 PUGI__CHECK_ERROR(status_bad_pi, s); 2132 3142 2133 3143 // determine node type; stricmp / strcasecmp is not portable 2134 3144 bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s; 2135 3145 2136 if (declaration ? OPTSET(parse_declaration) :OPTSET(parse_pi))3146 if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi)) 2137 3147 { 2138 3148 if (declaration) 2139 3149 { 2140 3150 // disallow non top-level declarations 2141 if (cursor->parent) THROW_ERROR(status_bad_pi, s);2142 2143 PU SHNODE(node_declaration);3151 if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s); 3152 3153 PUGI__PUSHNODE(node_declaration); 2144 3154 } 2145 3155 else 2146 3156 { 2147 PU SHNODE(node_pi);3157 PUGI__PUSHNODE(node_pi); 2148 3158 } 2149 3159 2150 3160 cursor->name = target; 2151 3161 2152 ENDSEG();3162 PUGI__ENDSEG(); 2153 3163 2154 3164 // parse value/attributes … … 2156 3166 { 2157 3167 // empty node 2158 if (! ENDSWITH(*s, '>'))THROW_ERROR(status_bad_pi, s);3168 if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s); 2159 3169 s += (*s == '>'); 2160 3170 2161 P OPNODE();2162 } 2163 else if ( IS_CHARTYPE(ch, ct_space))2164 { 2165 SKIPWS();3171 PUGI__POPNODE(); 3172 } 3173 else if (PUGI__IS_CHARTYPE(ch, ct_space)) 3174 { 3175 PUGI__SKIPWS(); 2166 3176 2167 3177 // scan for tag end 2168 3178 char_t* value = s; 2169 3179 2170 SCANFOR(s[0] == '?' &&ENDSWITH(s[1], '>'));2171 CHECK_ERROR(status_bad_pi, s);3180 PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>')); 3181 PUGI__CHECK_ERROR(status_bad_pi, s); 2172 3182 2173 3183 if (declaration) … … 2183 3193 // store value and step over > 2184 3194 cursor->value = value; 2185 POPNODE(); 2186 2187 ENDSEG(); 3195 3196 PUGI__POPNODE(); 3197 3198 PUGI__ENDSEG(); 2188 3199 2189 3200 s += (*s == '>'); 2190 3201 } 2191 3202 } 2192 else THROW_ERROR(status_bad_pi, s);3203 else PUGI__THROW_ERROR(status_bad_pi, s); 2193 3204 } 2194 3205 else 2195 3206 { 2196 3207 // scan for tag end 2197 SCANFOR(s[0] == '?' &&ENDSWITH(s[1], '>'));2198 CHECK_ERROR(status_bad_pi, s);3208 PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>')); 3209 PUGI__CHECK_ERROR(status_bad_pi, s); 2199 3210 2200 3211 s += (s[1] == '>' ? 2 : 1); … … 2207 3218 } 2208 3219 2209 void parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, char_t endch)3220 char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch) 2210 3221 { 2211 3222 strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); 2212 3223 strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); 2213 3224 2214 3225 char_t ch = 0; 2215 xml_node_struct* cursor = xmldoc;3226 xml_node_struct* cursor = root; 2216 3227 char_t* mark = s; 2217 3228 … … 2223 3234 2224 3235 LOC_TAG: 2225 if ( IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'3236 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...' 2226 3237 { 2227 PU SHNODE(node_element); // Append a new node to the tree.3238 PUGI__PUSHNODE(node_element); // Append a new node to the tree. 2228 3239 2229 3240 cursor->name = s; 2230 3241 2231 SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.2232 ENDSEG(); // Save char in 'ch', terminate & step over.3242 PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. 3243 PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. 2233 3244 2234 3245 if (ch == '>') … … 2236 3247 // end of tag 2237 3248 } 2238 else if ( IS_CHARTYPE(ch, ct_space))3249 else if (PUGI__IS_CHARTYPE(ch, ct_space)) 2239 3250 { 2240 3251 LOC_ATTRIBUTES: 2241 2242 2243 SKIPWS(); // Eat any whitespace.2244 2245 if ( IS_CHARTYPE(*s, ct_start_symbol)) // <... #...3252 while (true) 3253 { 3254 PUGI__SKIPWS(); // Eat any whitespace. 3255 3256 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... 2246 3257 { 2247 xml_attribute_struct* a = append_ attribute_ll(cursor,alloc); // Make space for this attribute.2248 if (!a) THROW_ERROR(status_out_of_memory, s);3258 xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute. 3259 if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); 2249 3260 2250 3261 a->name = s; // Save the offset. 2251 3262 2252 SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator. 2253 CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance 2254 2255 ENDSEG(); // Save char in 'ch', terminate & step over. 2256 CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance 2257 2258 if (IS_CHARTYPE(ch, ct_space)) 3263 PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. 3264 PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. 3265 3266 if (PUGI__IS_CHARTYPE(ch, ct_space)) 2259 3267 { 2260 SKIPWS(); // Eat any whitespace. 2261 CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance 3268 PUGI__SKIPWS(); // Eat any whitespace. 2262 3269 2263 3270 ch = *s; 2264 3271 ++s; 2265 3272 } 2266 3273 2267 3274 if (ch == '=') // '<... #=...' 2268 3275 { 2269 SKIPWS(); // Eat any whitespace.3276 PUGI__SKIPWS(); // Eat any whitespace. 2270 3277 2271 3278 if (*s == '"' || *s == '\'') // '<... #="...' … … 2276 3283 2277 3284 s = strconv_attribute(s, ch); 2278 2279 if (!s) THROW_ERROR(status_bad_attribute, a->value);3285 3286 if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); 2280 3287 2281 3288 // After this line the loop continues from the start; 2282 3289 // Whitespaces, / and > are ok, symbols and EOF are wrong, 2283 3290 // everything else will be detected 2284 if ( IS_CHARTYPE(*s, ct_start_symbol))THROW_ERROR(status_bad_attribute, s);3291 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s); 2285 3292 } 2286 else THROW_ERROR(status_bad_attribute, s);3293 else PUGI__THROW_ERROR(status_bad_attribute, s); 2287 3294 } 2288 else THROW_ERROR(status_bad_attribute, s);3295 else PUGI__THROW_ERROR(status_bad_attribute, s); 2289 3296 } 2290 3297 else if (*s == '/') 2291 3298 { 2292 3299 ++s; 2293 3300 2294 3301 if (*s == '>') 2295 3302 { 2296 P OPNODE();3303 PUGI__POPNODE(); 2297 3304 s++; 2298 3305 break; … … 2300 3307 else if (*s == 0 && endch == '>') 2301 3308 { 2302 P OPNODE();3309 PUGI__POPNODE(); 2303 3310 break; 2304 3311 } 2305 else THROW_ERROR(status_bad_start_element, s);3312 else PUGI__THROW_ERROR(status_bad_start_element, s); 2306 3313 } 2307 3314 else if (*s == '>') … … 2315 3322 break; 2316 3323 } 2317 else THROW_ERROR(status_bad_start_element, s);3324 else PUGI__THROW_ERROR(status_bad_start_element, s); 2318 3325 } 2319 3326 … … 2322 3329 else if (ch == '/') // '<#.../' 2323 3330 { 2324 if (! ENDSWITH(*s, '>'))THROW_ERROR(status_bad_start_element, s);2325 2326 P OPNODE(); // Pop.3331 if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s); 3332 3333 PUGI__POPNODE(); // Pop. 2327 3334 2328 3335 s += (*s == '>'); … … 2332 3339 // we stepped over null terminator, backtrack & handle closing tag 2333 3340 --s; 2334 2335 if (endch != '>') THROW_ERROR(status_bad_start_element, s);3341 3342 if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); 2336 3343 } 2337 else THROW_ERROR(status_bad_start_element, s);3344 else PUGI__THROW_ERROR(status_bad_start_element, s); 2338 3345 } 2339 3346 else if (*s == '/') … … 2341 3348 ++s; 2342 3349 3350 mark = s; 3351 2343 3352 char_t* name = cursor->name; 2344 if (!name) THROW_ERROR(status_end_element_mismatch, s);2345 2346 while ( IS_CHARTYPE(*s, ct_symbol))3353 if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, mark); 3354 3355 while (PUGI__IS_CHARTYPE(*s, ct_symbol)) 2347 3356 { 2348 if (*s++ != *name++) THROW_ERROR(status_end_element_mismatch, s);3357 if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark); 2349 3358 } 2350 3359 2351 3360 if (*name) 2352 3361 { 2353 if (*s == 0 && name[0] == endch && name[1] == 0) THROW_ERROR(status_bad_end_element, s);2354 else THROW_ERROR(status_end_element_mismatch, s);3362 if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); 3363 else PUGI__THROW_ERROR(status_end_element_mismatch, mark); 2355 3364 } 2356 2357 P OPNODE(); // Pop.2358 2359 SKIPWS();3365 3366 PUGI__POPNODE(); // Pop. 3367 3368 PUGI__SKIPWS(); 2360 3369 2361 3370 if (*s == 0) 2362 3371 { 2363 if (endch != '>') THROW_ERROR(status_bad_end_element, s);3372 if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s); 2364 3373 } 2365 3374 else 2366 3375 { 2367 if (*s != '>') THROW_ERROR(status_bad_end_element, s);3376 if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s); 2368 3377 ++s; 2369 3378 } … … 2372 3381 { 2373 3382 s = parse_question(s, cursor, optmsk, endch); 3383 if (!s) return s; 2374 3384 2375 3385 assert(cursor); 2376 if ( (cursor->header & xml_memory_page_type_mask) + 1== node_declaration) goto LOC_ATTRIBUTES;3386 if (PUGI__NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES; 2377 3387 } 2378 3388 else if (*s == '!') // '<!...' 2379 3389 { 2380 3390 s = parse_exclamation(s, cursor, optmsk, endch); 3391 if (!s) return s; 2381 3392 } 2382 else if (*s == 0 && endch == '?') THROW_ERROR(status_bad_pi, s);2383 else THROW_ERROR(status_unrecognized_tag, s);3393 else if (*s == 0 && endch == '?') PUGI__THROW_ERROR(status_bad_pi, s); 3394 else PUGI__THROW_ERROR(status_unrecognized_tag, s); 2384 3395 } 2385 3396 else … … 2387 3398 mark = s; // Save this offset while searching for a terminator. 2388 3399 2389 SKIPWS(); // Eat whitespace if no genuine PCDATA here.2390 2391 if ( (!OPTSET(parse_ws_pcdata) || mark == s) && (*s == '<' || !*s))3400 PUGI__SKIPWS(); // Eat whitespace if no genuine PCDATA here. 3401 3402 if (*s == '<' || !*s) 2392 3403 { 2393 continue; 3404 // We skipped some whitespace characters because otherwise we would take the tag branch instead of PCDATA one 3405 assert(mark != s); 3406 3407 if (!PUGI__OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) || PUGI__OPTSET(parse_trim_pcdata)) 3408 { 3409 continue; 3410 } 3411 else if (PUGI__OPTSET(parse_ws_pcdata_single)) 3412 { 3413 if (s[0] != '<' || s[1] != '/' || cursor->first_child) continue; 3414 } 2394 3415 } 2395 3416 2396 s = mark; 2397 2398 if (cursor->parent) 3417 if (!PUGI__OPTSET(parse_trim_pcdata)) 3418 s = mark; 3419 3420 if (cursor->parent || PUGI__OPTSET(parse_fragment)) 2399 3421 { 2400 PUSHNODE(node_pcdata); // Append a new node on the tree. 2401 cursor->value = s; // Save the offset. 3422 if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value) 3423 { 3424 cursor->value = s; // Save the offset. 3425 } 3426 else 3427 { 3428 PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. 3429 3430 cursor->value = s; // Save the offset. 3431 3432 PUGI__POPNODE(); // Pop since this is a standalone. 3433 } 2402 3434 2403 3435 s = strconv_pcdata(s); 2404 2405 POPNODE(); // Pop since this is a standalone. 2406 3436 2407 3437 if (!*s) break; 2408 3438 } 2409 3439 else 2410 3440 { 2411 SCANFOR(*s == '<'); // '...<'3441 PUGI__SCANFOR(*s == '<'); // '...<' 2412 3442 if (!*s) break; 2413 3443 2414 3444 ++s; 2415 3445 } … … 2421 3451 2422 3452 // check that last tag is closed 2423 if (cursor != xmldoc) THROW_ERROR(status_end_element_mismatch, s); 2424 } 2425 2426 static xml_parse_result parse(char_t* buffer, size_t length, xml_node_struct* root, unsigned int optmsk) 2427 { 2428 xml_document_struct* xmldoc = static_cast<xml_document_struct*>(root); 2429 2430 // store buffer for offset_debug 2431 xmldoc->buffer = buffer; 2432 3453 if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s); 3454 3455 return s; 3456 } 3457 3458 #ifdef PUGIXML_WCHAR_MODE 3459 static char_t* parse_skip_bom(char_t* s) 3460 { 3461 unsigned int bom = 0xfeff; 3462 return (s[0] == static_cast<wchar_t>(bom)) ? s + 1 : s; 3463 } 3464 #else 3465 static char_t* parse_skip_bom(char_t* s) 3466 { 3467 return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s; 3468 } 3469 #endif 3470 3471 static bool has_element_node_siblings(xml_node_struct* node) 3472 { 3473 while (node) 3474 { 3475 if (PUGI__NODETYPE(node) == node_element) return true; 3476 3477 node = node->next_sibling; 3478 } 3479 3480 return false; 3481 } 3482 3483 static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk) 3484 { 2433 3485 // early-out for empty documents 2434 if (length == 0) return make_parse_result(status_ok); 3486 if (length == 0) 3487 return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element); 3488 3489 // get last child of the root before parsing 3490 xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0; 2435 3491 2436 3492 // create parser on stack 2437 xml_parser parser( *xmldoc);3493 xml_parser parser(static_cast<xml_allocator*>(xmldoc)); 2438 3494 2439 3495 // save last character and make buffer zero-terminated (speeds up parsing) 2440 3496 char_t endch = buffer[length - 1]; 2441 3497 buffer[length - 1] = 0; 2442 3498 3499 // skip BOM to make sure it does not end up as part of parse output 3500 char_t* buffer_data = parse_skip_bom(buffer); 3501 2443 3502 // perform actual parsing 2444 int error = setjmp(parser.error_handler); 2445 2446 if (error == 0) 2447 { 2448 parser.parse(buffer, xmldoc, optmsk, endch); 2449 } 2450 2451 xml_parse_result result = make_parse_result(static_cast<xml_parse_status>(error), parser.error_offset ? parser.error_offset - buffer : 0); 3503 parser.parse_tree(buffer_data, root, optmsk, endch); 3504 3505 xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0); 2452 3506 assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length); 2453 3507 2454 // update allocator state 2455 *static_cast<xml_allocator*>(xmldoc) = parser.alloc; 2456 2457 // since we removed last character, we have to handle the only possible false positive 2458 if (result && endch == '<') 2459 { 2460 // there's no possible well-formed document with < at the end 2461 return make_parse_result(status_unrecognized_tag, length); 3508 if (result) 3509 { 3510 // since we removed last character, we have to handle the only possible false positive (stray <) 3511 if (endch == '<') 3512 return make_parse_result(status_unrecognized_tag, length - 1); 3513 3514 // check if there are any element nodes parsed 3515 xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0; 3516 3517 if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed)) 3518 return make_parse_result(status_no_document_element, length - 1); 3519 } 3520 else 3521 { 3522 // roll back offset if it occurs on a null terminator in the source buffer 3523 if (result.offset > 0 && static_cast<size_t>(result.offset) == length - 1 && endch == 0) 3524 result.offset--; 2462 3525 } 2463 3526 … … 2467 3530 2468 3531 // Output facilities 2469 xml_encoding get_write_native_encoding()3532 PUGI__FN xml_encoding get_write_native_encoding() 2470 3533 { 2471 3534 #ifdef PUGIXML_WCHAR_MODE … … 2476 3539 } 2477 3540 2478 xml_encoding get_write_encoding(xml_encoding encoding)3541 PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding) 2479 3542 { 2480 3543 // replace wchar encoding with utf implementation … … 2494 3557 } 2495 3558 3559 template <typename D, typename T> PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T) 3560 { 3561 PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); 3562 3563 typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T()); 3564 3565 return static_cast<size_t>(end - dest) * sizeof(*dest); 3566 } 3567 3568 template <typename D, typename T> PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap) 3569 { 3570 PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type)); 3571 3572 typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T()); 3573 3574 if (opt_swap) 3575 { 3576 for (typename T::value_type i = dest; i != end; ++i) 3577 *i = endian_swap(*i); 3578 } 3579 3580 return static_cast<size_t>(end - dest) * sizeof(*dest); 3581 } 3582 2496 3583 #ifdef PUGIXML_WCHAR_MODE 2497 size_t get_valid_length(const char_t* data, size_t length)2498 { 2499 assert(length > 0);2500 2501 // discard last character if it's the lead of a surrogate pair 2502 return (sizeof(wchar_t) == 2 && (unsigned)(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;2503 } 2504 2505 size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding)3584 PUGI__FN size_t get_valid_length(const char_t* data, size_t length) 3585 { 3586 if (length < 1) return 0; 3587 3588 // discard last character if it's the lead of a surrogate pair 3589 return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; 3590 } 3591 3592 PUGI__FN size_t convert_buffer_output(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) 2506 3593 { 2507 3594 // only endian-swapping is required 2508 3595 if (need_endian_swap_utf(encoding, get_wchar_encoding())) 2509 3596 { 2510 convert_wchar_endian_swap(r einterpret_cast<char_t*>(result), data, length);3597 convert_wchar_endian_swap(r_char, data, length); 2511 3598 2512 3599 return length * sizeof(char_t); 2513 3600 } 2514 3601 2515 3602 // convert to utf8 2516 3603 if (encoding == encoding_utf8) 2517 { 2518 uint8_t* dest = reinterpret_cast<uint8_t*>(result); 2519 2520 uint8_t* end = sizeof(wchar_t) == 2 ? 2521 utf_decoder<utf8_writer>::decode_utf16_block(reinterpret_cast<const uint16_t*>(data), length, dest) : 2522 utf_decoder<utf8_writer>::decode_utf32_block(reinterpret_cast<const uint32_t*>(data), length, dest); 2523 2524 return static_cast<size_t>(end - dest); 2525 } 3604 return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer()); 2526 3605 2527 3606 // convert to utf16 2528 3607 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) 2529 3608 { 2530 uint16_t* dest = reinterpret_cast<uint16_t*>(result);2531 2532 // convert to native utf162533 uint16_t* end = utf_decoder<utf16_writer>::decode_utf32_block(reinterpret_cast<const uint32_t*>(data), length, dest);2534 2535 // swap if necessary2536 3609 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; 2537 3610 2538 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest)); 2539 2540 return static_cast<size_t>(end - dest) * sizeof(uint16_t); 3611 return convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding); 2541 3612 } 2542 3613 … … 2544 3615 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) 2545 3616 { 2546 uint32_t* dest = reinterpret_cast<uint32_t*>(result);2547 2548 // convert to native utf322549 uint32_t* end = utf_decoder<utf32_writer>::decode_utf16_block(reinterpret_cast<const uint16_t*>(data), length, dest);2550 2551 // swap if necessary2552 3617 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; 2553 3618 2554 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest)); 2555 2556 return static_cast<size_t>(end - dest) * sizeof(uint32_t); 2557 } 2558 2559 assert(!"Invalid encoding"); 3619 return convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding); 3620 } 3621 3622 // convert to latin1 3623 if (encoding == encoding_latin1) 3624 return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer()); 3625 3626 assert(false && "Invalid encoding"); 2560 3627 return 0; 2561 3628 } 2562 3629 #else 2563 size_t get_valid_length(const char_t* data, size_t length)2564 { 2565 assert(length > 4);3630 PUGI__FN size_t get_valid_length(const char_t* data, size_t length) 3631 { 3632 if (length < 5) return 0; 2566 3633 2567 3634 for (size_t i = 1; i <= 4; ++i) … … 2577 3644 } 2578 3645 2579 size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding)3646 PUGI__FN size_t convert_buffer_output(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) 2580 3647 { 2581 3648 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) 2582 3649 { 2583 uint16_t* dest = reinterpret_cast<uint16_t*>(result);2584 2585 // convert to native utf162586 uint16_t* end = utf_decoder<utf16_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);2587 2588 // swap if necessary2589 3650 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be; 2590 3651 2591 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest)); 2592 2593 return static_cast<size_t>(end - dest) * sizeof(uint16_t); 3652 return convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding); 2594 3653 } 2595 3654 2596 3655 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) 2597 3656 { 2598 uint32_t* dest = reinterpret_cast<uint32_t*>(result);2599 2600 // convert to native utf322601 uint32_t* end = utf_decoder<utf32_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);2602 2603 // swap if necessary2604 3657 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be; 2605 3658 2606 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest)); 2607 2608 return static_cast<size_t>(end - dest) * sizeof(uint32_t); 2609 } 2610 2611 assert(!"Invalid encoding"); 3659 return convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding); 3660 } 3661 3662 if (encoding == encoding_latin1) 3663 return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer()); 3664 3665 assert(false && "Invalid encoding"); 2612 3666 return 0; 2613 3667 } … … 2620 3674 2621 3675 public: 2622 xml_buffered_writer(xml_writer& writer, xml_encoding user_encoding): writer(writer), bufsize(0), encoding(get_write_encoding(user_encoding)) 2623 { 2624 } 2625 2626 ~xml_buffered_writer() 2627 { 2628 flush(); 2629 } 2630 2631 void flush() 3676 xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding)) 3677 { 3678 PUGI__STATIC_ASSERT(bufcapacity >= 8); 3679 } 3680 3681 size_t flush() 2632 3682 { 2633 3683 flush(buffer, bufsize); 2634 3684 bufsize = 0; 3685 return 0; 2635 3686 } 2636 3687 … … 2645 3696 { 2646 3697 // convert chunk 2647 size_t result = convert_buffer (scratch, data, size, encoding);3698 size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding); 2648 3699 assert(result <= sizeof(scratch)); 2649 3700 2650 3701 // write data 2651 writer.write(scratch, result); 2652 } 2653 } 2654 2655 void write(const char_t* data, size_t length) 2656 { 2657 if (bufsize + length > bufcapacity) 2658 { 2659 // flush the remaining buffer contents 2660 flush(); 2661 2662 // handle large chunks 2663 if (length > bufcapacity) 2664 { 2665 if (encoding == get_write_native_encoding()) 2666 { 2667 // fast path, can just write data chunk 2668 writer.write(data, length * sizeof(char_t)); 2669 return; 2670 } 2671 2672 // need to convert in suitable chunks 2673 while (length > bufcapacity) 2674 { 2675 // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer 2676 // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) 2677 size_t chunk_size = get_valid_length(data, bufcapacity); 2678 2679 // convert chunk and write 2680 flush(data, chunk_size); 2681 2682 // iterate 2683 data += chunk_size; 2684 length -= chunk_size; 2685 } 2686 2687 // small tail is copied below 2688 bufsize = 0; 2689 } 3702 writer.write(scratch.data_u8, result); 3703 } 3704 } 3705 3706 void write_direct(const char_t* data, size_t length) 3707 { 3708 // flush the remaining buffer contents 3709 flush(); 3710 3711 // handle large chunks 3712 if (length > bufcapacity) 3713 { 3714 if (encoding == get_write_native_encoding()) 3715 { 3716 // fast path, can just write data chunk 3717 writer.write(data, length * sizeof(char_t)); 3718 return; 3719 } 3720 3721 // need to convert in suitable chunks 3722 while (length > bufcapacity) 3723 { 3724 // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer 3725 // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary) 3726 size_t chunk_size = get_valid_length(data, bufcapacity); 3727 assert(chunk_size); 3728 3729 // convert chunk and write 3730 flush(data, chunk_size); 3731 3732 // iterate 3733 data += chunk_size; 3734 length -= chunk_size; 3735 } 3736 3737 // small tail is copied below 3738 bufsize = 0; 2690 3739 } 2691 3740 … … 2694 3743 } 2695 3744 2696 void write(const char_t* data) 2697 { 2698 write(data, strlength(data)); 3745 void write_buffer(const char_t* data, size_t length) 3746 { 3747 size_t offset = bufsize; 3748 3749 if (offset + length <= bufcapacity) 3750 { 3751 memcpy(buffer + offset, data, length * sizeof(char_t)); 3752 bufsize = offset + length; 3753 } 3754 else 3755 { 3756 write_direct(data, length); 3757 } 3758 } 3759 3760 void write_string(const char_t* data) 3761 { 3762 // write the part of the string that fits in the buffer 3763 size_t offset = bufsize; 3764 3765 while (*data && offset < bufcapacity) 3766 buffer[offset++] = *data++; 3767 3768 // write the rest 3769 if (offset < bufcapacity) 3770 { 3771 bufsize = offset; 3772 } 3773 else 3774 { 3775 // backtrack a bit if we have split the codepoint 3776 size_t length = offset - bufsize; 3777 size_t extra = length - get_valid_length(data - length, length); 3778 3779 bufsize = offset - extra; 3780 3781 write_direct(data - extra, strlength(data) + extra); 3782 } 2699 3783 } 2700 3784 2701 3785 void write(char_t d0) 2702 3786 { 2703 if (bufsize + 1 > bufcapacity) flush(); 2704 2705 buffer[bufsize + 0] = d0; 2706 bufsize += 1; 3787 size_t offset = bufsize; 3788 if (offset > bufcapacity - 1) offset = flush(); 3789 3790 buffer[offset + 0] = d0; 3791 bufsize = offset + 1; 2707 3792 } 2708 3793 2709 3794 void write(char_t d0, char_t d1) 2710 3795 { 2711 if (bufsize + 2 > bufcapacity) flush(); 2712 2713 buffer[bufsize + 0] = d0; 2714 buffer[bufsize + 1] = d1; 2715 bufsize += 2; 3796 size_t offset = bufsize; 3797 if (offset > bufcapacity - 2) offset = flush(); 3798 3799 buffer[offset + 0] = d0; 3800 buffer[offset + 1] = d1; 3801 bufsize = offset + 2; 2716 3802 } 2717 3803 2718 3804 void write(char_t d0, char_t d1, char_t d2) 2719 3805 { 2720 if (bufsize + 3 > bufcapacity) flush(); 2721 2722 buffer[bufsize + 0] = d0; 2723 buffer[bufsize + 1] = d1; 2724 buffer[bufsize + 2] = d2; 2725 bufsize += 3; 3806 size_t offset = bufsize; 3807 if (offset > bufcapacity - 3) offset = flush(); 3808 3809 buffer[offset + 0] = d0; 3810 buffer[offset + 1] = d1; 3811 buffer[offset + 2] = d2; 3812 bufsize = offset + 3; 2726 3813 } 2727 3814 2728 3815 void write(char_t d0, char_t d1, char_t d2, char_t d3) 2729 3816 { 2730 if (bufsize + 4 > bufcapacity) flush(); 2731 2732 buffer[bufsize + 0] = d0; 2733 buffer[bufsize + 1] = d1; 2734 buffer[bufsize + 2] = d2; 2735 buffer[bufsize + 3] = d3; 2736 bufsize += 4; 3817 size_t offset = bufsize; 3818 if (offset > bufcapacity - 4) offset = flush(); 3819 3820 buffer[offset + 0] = d0; 3821 buffer[offset + 1] = d1; 3822 buffer[offset + 2] = d2; 3823 buffer[offset + 3] = d3; 3824 bufsize = offset + 4; 2737 3825 } 2738 3826 2739 3827 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) 2740 3828 { 2741 if (bufsize + 5 > bufcapacity) flush(); 2742 2743 buffer[bufsize + 0] = d0; 2744 buffer[bufsize + 1] = d1; 2745 buffer[bufsize + 2] = d2; 2746 buffer[bufsize + 3] = d3; 2747 buffer[bufsize + 4] = d4; 2748 bufsize += 5; 3829 size_t offset = bufsize; 3830 if (offset > bufcapacity - 5) offset = flush(); 3831 3832 buffer[offset + 0] = d0; 3833 buffer[offset + 1] = d1; 3834 buffer[offset + 2] = d2; 3835 buffer[offset + 3] = d3; 3836 buffer[offset + 4] = d4; 3837 bufsize = offset + 5; 2749 3838 } 2750 3839 2751 3840 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) 2752 3841 { 2753 if (bufsize + 6 > bufcapacity) flush(); 2754 2755 buffer[bufsize + 0] = d0; 2756 buffer[bufsize + 1] = d1; 2757 buffer[bufsize + 2] = d2; 2758 buffer[bufsize + 3] = d3; 2759 buffer[bufsize + 4] = d4; 2760 buffer[bufsize + 5] = d5; 2761 bufsize += 6; 3842 size_t offset = bufsize; 3843 if (offset > bufcapacity - 6) offset = flush(); 3844 3845 buffer[offset + 0] = d0; 3846 buffer[offset + 1] = d1; 3847 buffer[offset + 2] = d2; 3848 buffer[offset + 3] = d3; 3849 buffer[offset + 4] = d4; 3850 buffer[offset + 5] = d5; 3851 bufsize = offset + 6; 2762 3852 } 2763 3853 … … 2765 3855 // utf16 maximum expansion: x2 (-> utf32) 2766 3856 // utf32 maximum expansion: x1 2767 enum { bufcapacity = 2048 }; 3857 enum 3858 { 3859 bufcapacitybytes = 3860 #ifdef PUGIXML_MEMORY_OUTPUT_STACK 3861 PUGIXML_MEMORY_OUTPUT_STACK 3862 #else 3863 10240 3864 #endif 3865 , 3866 bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4) 3867 }; 2768 3868 2769 3869 char_t buffer[bufcapacity]; 2770 char scratch[4 * bufcapacity]; 3870 3871 union 3872 { 3873 uint8_t data_u8[4 * bufcapacity]; 3874 uint16_t data_u16[2 * bufcapacity]; 3875 uint32_t data_u32[bufcapacity]; 3876 char_t data_char[bufcapacity]; 3877 } scratch; 2771 3878 2772 3879 xml_writer& writer; … … 2775 3882 }; 2776 3883 2777 void write_bom(xml_writer& writer, xml_encoding encoding) 2778 { 2779 switch (encoding) 2780 { 2781 case encoding_utf8: 2782 writer.write("\xef\xbb\xbf", 3); 2783 break; 2784 2785 case encoding_utf16_be: 2786 writer.write("\xfe\xff", 2); 2787 break; 2788 2789 case encoding_utf16_le: 2790 writer.write("\xff\xfe", 2); 2791 break; 2792 2793 case encoding_utf32_be: 2794 writer.write("\x00\x00\xfe\xff", 4); 2795 break; 2796 2797 case encoding_utf32_le: 2798 writer.write("\xff\xfe\x00\x00", 4); 2799 break; 2800 2801 default: 2802 assert(!"Invalid encoding"); 2803 } 2804 } 2805 2806 void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) 3884 PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) 2807 3885 { 2808 3886 while (*s) 2809 3887 { 2810 3888 const char_t* prev = s; 2811 3889 2812 3890 // While *s is a usual symbol 2813 while (!IS_CHARTYPEX(*s, type)) ++s;2814 2815 writer.write (prev, static_cast<size_t>(s - prev));3891 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type)); 3892 3893 writer.write_buffer(prev, static_cast<size_t>(s - prev)); 2816 3894 2817 3895 switch (*s) … … 2845 3923 } 2846 3924 2847 void text_output_cdata(xml_buffered_writer& writer, const char_t* s) 3925 PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags) 3926 { 3927 if (flags & format_no_escapes) 3928 writer.write_string(s); 3929 else 3930 text_output_escaped(writer, s, type); 3931 } 3932 3933 PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s) 2848 3934 { 2849 3935 do … … 2860 3946 if (*s) s += 2; 2861 3947 2862 writer.write (prev, static_cast<size_t>(s - prev));3948 writer.write_buffer(prev, static_cast<size_t>(s - prev)); 2863 3949 2864 3950 writer.write(']', ']', '>'); … … 2867 3953 } 2868 3954 2869 void node_output_attributes(xml_buffered_writer& writer, const xml_node& node) 3955 PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth) 3956 { 3957 switch (indent_length) 3958 { 3959 case 1: 3960 { 3961 for (unsigned int i = 0; i < depth; ++i) 3962 writer.write(indent[0]); 3963 break; 3964 } 3965 3966 case 2: 3967 { 3968 for (unsigned int i = 0; i < depth; ++i) 3969 writer.write(indent[0], indent[1]); 3970 break; 3971 } 3972 3973 case 3: 3974 { 3975 for (unsigned int i = 0; i < depth; ++i) 3976 writer.write(indent[0], indent[1], indent[2]); 3977 break; 3978 } 3979 3980 case 4: 3981 { 3982 for (unsigned int i = 0; i < depth; ++i) 3983 writer.write(indent[0], indent[1], indent[2], indent[3]); 3984 break; 3985 } 3986 3987 default: 3988 { 3989 for (unsigned int i = 0; i < depth; ++i) 3990 writer.write_buffer(indent, indent_length); 3991 } 3992 } 3993 } 3994 3995 PUGI__FN void node_output_comment(xml_buffered_writer& writer, const char_t* s) 3996 { 3997 writer.write('<', '!', '-', '-'); 3998 3999 while (*s) 4000 { 4001 const char_t* prev = s; 4002 4003 // look for -\0 or -- sequence - we can't output it since -- is illegal in comment body 4004 while (*s && !(s[0] == '-' && (s[1] == '-' || s[1] == 0))) ++s; 4005 4006 writer.write_buffer(prev, static_cast<size_t>(s - prev)); 4007 4008 if (*s) 4009 { 4010 assert(*s == '-'); 4011 4012 writer.write('-', ' '); 4013 ++s; 4014 } 4015 } 4016 4017 writer.write('-', '-', '>'); 4018 } 4019 4020 PUGI__FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s) 4021 { 4022 while (*s) 4023 { 4024 const char_t* prev = s; 4025 4026 // look for ?> sequence - we can't output it since ?> terminates PI 4027 while (*s && !(s[0] == '?' && s[1] == '>')) ++s; 4028 4029 writer.write_buffer(prev, static_cast<size_t>(s - prev)); 4030 4031 if (*s) 4032 { 4033 assert(s[0] == '?' && s[1] == '>'); 4034 4035 writer.write('?', ' ', '>'); 4036 s += 2; 4037 } 4038 } 4039 } 4040 4041 PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) 2870 4042 { 2871 4043 const char_t* default_name = PUGIXML_TEXT(":anonymous"); 2872 4044 2873 for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute()) 2874 { 2875 writer.write(' '); 2876 writer.write(a.name()[0] ? a.name() : default_name); 4045 for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) 4046 { 4047 if ((flags & (format_indent_attributes | format_raw)) == format_indent_attributes) 4048 { 4049 writer.write('\n'); 4050 4051 text_output_indent(writer, indent, indent_length, depth + 1); 4052 } 4053 else 4054 { 4055 writer.write(' '); 4056 } 4057 4058 writer.write_string(a->name ? a->name + 0 : default_name); 2877 4059 writer.write('=', '"'); 2878 4060 2879 text_output_escaped(writer, a.value(), ctx_special_attr); 4061 if (a->value) 4062 text_output(writer, a->value, ctx_special_attr, flags); 2880 4063 2881 4064 writer.write('"'); … … 2883 4066 } 2884 4067 2885 void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth)4068 PUGI__FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth) 2886 4069 { 2887 4070 const char_t* default_name = PUGIXML_TEXT(":anonymous"); 2888 2889 if ((flags & format_indent) != 0 && (flags & format_raw) == 0) 2890 for (unsigned int i = 0; i < depth; ++i) writer.write(indent); 2891 2892 switch (node.type()) 2893 { 2894 case node_document: 2895 { 2896 for (xml_node n = node.first_child(); n; n = n.next_sibling()) 2897 node_output(writer, n, indent, flags, depth); 2898 break; 2899 } 2900 2901 case node_element: 2902 { 2903 const char_t* name = node.name()[0] ? node.name() : default_name; 2904 2905 writer.write('<'); 2906 writer.write(name); 2907 2908 node_output_attributes(writer, node); 2909 2910 if (flags & format_raw) 2911 { 2912 if (!node.first_child()) 2913 writer.write(' ', '/', '>'); 4071 const char_t* name = node->name ? node->name + 0 : default_name; 4072 4073 writer.write('<'); 4074 writer.write_string(name); 4075 4076 if (node->first_attribute) 4077 node_output_attributes(writer, node, indent, indent_length, flags, depth); 4078 4079 // element nodes can have value if parse_embed_pcdata was used 4080 if (!node->value) 4081 { 4082 if (!node->first_child) 4083 { 4084 if (flags & format_no_empty_element_tags) 4085 { 4086 writer.write('>', '<', '/'); 4087 writer.write_string(name); 4088 writer.write('>'); 4089 4090 return false; 4091 } 2914 4092 else 2915 4093 { 2916 writer.write('>'); 2917 2918 for (xml_node n = node.first_child(); n; n = n.next_sibling()) 2919 node_output(writer, n, indent, flags, depth + 1); 2920 2921 writer.write('<', '/'); 2922 writer.write(name); 2923 writer.write('>'); 2924 } 2925 } 2926 else if (!node.first_child()) 2927 writer.write(' ', '/', '>', '\n'); 2928 else if (node.first_child() == node.last_child() && (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata)) 4094 if ((flags & format_raw) == 0) 4095 writer.write(' '); 4096 4097 writer.write('/', '>'); 4098 4099 return false; 4100 } 4101 } 4102 else 2929 4103 { 2930 4104 writer.write('>'); 2931 4105 2932 if (node.first_child().type() == node_pcdata) 2933 text_output_escaped(writer, node.first_child().value(), ctx_special_pcdata); 2934 else 2935 text_output_cdata(writer, node.first_child().value()); 2936 4106 return true; 4107 } 4108 } 4109 else 4110 { 4111 writer.write('>'); 4112 4113 text_output(writer, node->value, ctx_special_pcdata, flags); 4114 4115 if (!node->first_child) 4116 { 2937 4117 writer.write('<', '/'); 2938 writer.write(name); 2939 writer.write('>', '\n'); 4118 writer.write_string(name); 4119 writer.write('>'); 4120 4121 return false; 2940 4122 } 2941 4123 else 2942 4124 { 2943 writer.write('>', '\n'); 2944 2945 for (xml_node n = node.first_child(); n; n = n.next_sibling()) 2946 node_output(writer, n, indent, flags, depth + 1); 2947 2948 if ((flags & format_indent) != 0 && (flags & format_raw) == 0) 2949 for (unsigned int i = 0; i < depth; ++i) writer.write(indent); 2950 2951 writer.write('<', '/'); 2952 writer.write(name); 2953 writer.write('>', '\n'); 2954 } 2955 2956 break; 2957 } 2958 2959 case node_pcdata: 2960 text_output_escaped(writer, node.value(), ctx_special_pcdata); 2961 if ((flags & format_raw) == 0) writer.write('\n'); 2962 break; 2963 2964 case node_cdata: 2965 text_output_cdata(writer, node.value()); 2966 if ((flags & format_raw) == 0) writer.write('\n'); 2967 break; 2968 2969 case node_comment: 2970 writer.write('<', '!', '-', '-'); 2971 writer.write(node.value()); 2972 writer.write('-', '-', '>'); 2973 if ((flags & format_raw) == 0) writer.write('\n'); 2974 break; 2975 2976 case node_pi: 2977 case node_declaration: 2978 writer.write('<', '?'); 2979 writer.write(node.name()[0] ? node.name() : default_name); 2980 2981 if (node.type() == node_declaration) 2982 { 2983 node_output_attributes(writer, node); 2984 } 2985 else if (node.value()[0]) 2986 { 2987 writer.write(' '); 2988 writer.write(node.value()); 2989 } 2990 2991 writer.write('?', '>'); 2992 if ((flags & format_raw) == 0) writer.write('\n'); 2993 break; 2994 2995 case node_doctype: 2996 writer.write('<', '!', 'D', 'O', 'C'); 2997 writer.write('T', 'Y', 'P', 'E'); 2998 2999 if (node.value()[0]) 3000 { 3001 writer.write(' '); 3002 writer.write(node.value()); 3003 } 3004 3005 writer.write('>'); 3006 if ((flags & format_raw) == 0) writer.write('\n'); 3007 break; 3008 3009 default: 3010 assert(!"Invalid node type"); 3011 } 3012 } 3013 3014 inline bool has_declaration(const xml_node& node) 3015 { 3016 for (xml_node child = node.first_child(); child; child = child.next_sibling()) 3017 { 3018 xml_node_type type = child.type(); 4125 return true; 4126 } 4127 } 4128 } 4129 4130 PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node) 4131 { 4132 const char_t* default_name = PUGIXML_TEXT(":anonymous"); 4133 const char_t* name = node->name ? node->name + 0 : default_name; 4134 4135 writer.write('<', '/'); 4136 writer.write_string(name); 4137 writer.write('>'); 4138 } 4139 4140 PUGI__FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags) 4141 { 4142 const char_t* default_name = PUGIXML_TEXT(":anonymous"); 4143 4144 switch (PUGI__NODETYPE(node)) 4145 { 4146 case node_pcdata: 4147 text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""), ctx_special_pcdata, flags); 4148 break; 4149 4150 case node_cdata: 4151 text_output_cdata(writer, node->value ? node->value + 0 : PUGIXML_TEXT("")); 4152 break; 4153 4154 case node_comment: 4155 node_output_comment(writer, node->value ? node->value + 0 : PUGIXML_TEXT("")); 4156 break; 4157 4158 case node_pi: 4159 writer.write('<', '?'); 4160 writer.write_string(node->name ? node->name + 0 : default_name); 4161 4162 if (node->value) 4163 { 4164 writer.write(' '); 4165 node_output_pi_value(writer, node->value); 4166 } 4167 4168 writer.write('?', '>'); 4169 break; 4170 4171 case node_declaration: 4172 writer.write('<', '?'); 4173 writer.write_string(node->name ? node->name + 0 : default_name); 4174 node_output_attributes(writer, node, PUGIXML_TEXT(""), 0, flags | format_raw, 0); 4175 writer.write('?', '>'); 4176 break; 4177 4178 case node_doctype: 4179 writer.write('<', '!', 'D', 'O', 'C'); 4180 writer.write('T', 'Y', 'P', 'E'); 4181 4182 if (node->value) 4183 { 4184 writer.write(' '); 4185 writer.write_string(node->value); 4186 } 4187 4188 writer.write('>'); 4189 break; 4190 4191 default: 4192 assert(false && "Invalid node type"); 4193 } 4194 } 4195 4196 enum indent_flags_t 4197 { 4198 indent_newline = 1, 4199 indent_indent = 2 4200 }; 4201 4202 PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth) 4203 { 4204 size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0; 4205 unsigned int indent_flags = indent_indent; 4206 4207 xml_node_struct* node = root; 4208 4209 do 4210 { 4211 assert(node); 4212 4213 // begin writing current node 4214 if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata) 4215 { 4216 node_output_simple(writer, node, flags); 4217 4218 indent_flags = 0; 4219 } 4220 else 4221 { 4222 if ((indent_flags & indent_newline) && (flags & format_raw) == 0) 4223 writer.write('\n'); 4224 4225 if ((indent_flags & indent_indent) && indent_length) 4226 text_output_indent(writer, indent, indent_length, depth); 4227 4228 if (PUGI__NODETYPE(node) == node_element) 4229 { 4230 indent_flags = indent_newline | indent_indent; 4231 4232 if (node_output_start(writer, node, indent, indent_length, flags, depth)) 4233 { 4234 // element nodes can have value if parse_embed_pcdata was used 4235 if (node->value) 4236 indent_flags = 0; 4237 4238 node = node->first_child; 4239 depth++; 4240 continue; 4241 } 4242 } 4243 else if (PUGI__NODETYPE(node) == node_document) 4244 { 4245 indent_flags = indent_indent; 4246 4247 if (node->first_child) 4248 { 4249 node = node->first_child; 4250 continue; 4251 } 4252 } 4253 else 4254 { 4255 node_output_simple(writer, node, flags); 4256 4257 indent_flags = indent_newline | indent_indent; 4258 } 4259 } 4260 4261 // continue to the next node 4262 while (node != root) 4263 { 4264 if (node->next_sibling) 4265 { 4266 node = node->next_sibling; 4267 break; 4268 } 4269 4270 node = node->parent; 4271 4272 // write closing node 4273 if (PUGI__NODETYPE(node) == node_element) 4274 { 4275 depth--; 4276 4277 if ((indent_flags & indent_newline) && (flags & format_raw) == 0) 4278 writer.write('\n'); 4279 4280 if ((indent_flags & indent_indent) && indent_length) 4281 text_output_indent(writer, indent, indent_length, depth); 4282 4283 node_output_end(writer, node); 4284 4285 indent_flags = indent_newline | indent_indent; 4286 } 4287 } 4288 } 4289 while (node != root); 4290 4291 if ((indent_flags & indent_newline) && (flags & format_raw) == 0) 4292 writer.write('\n'); 4293 } 4294 4295 PUGI__FN bool has_declaration(xml_node_struct* node) 4296 { 4297 for (xml_node_struct* child = node->first_child; child; child = child->next_sibling) 4298 { 4299 xml_node_type type = PUGI__NODETYPE(child); 3019 4300 3020 4301 if (type == node_declaration) return true; … … 3025 4306 } 3026 4307 3027 inline bool allow_insert_child(xml_node_type parent, xml_node_type child) 4308 PUGI__FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node) 4309 { 4310 for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute) 4311 if (a == attr) 4312 return true; 4313 4314 return false; 4315 } 4316 4317 PUGI__FN bool allow_insert_attribute(xml_node_type parent) 4318 { 4319 return parent == node_element || parent == node_declaration; 4320 } 4321 4322 PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child) 3028 4323 { 3029 4324 if (parent != node_document && parent != node_element) return false; … … 3034 4329 } 3035 4330 3036 void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip) 3037 { 3038 assert(dest.type() == source.type()); 3039 3040 switch (source.type()) 3041 { 3042 case node_element: 3043 { 3044 dest.set_name(source.name()); 3045 3046 for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) 3047 dest.append_attribute(a.name()).set_value(a.value()); 3048 3049 for (xml_node c = source.first_child(); c; c = c.next_sibling()) 3050 { 3051 if (c == skip) continue; 3052 3053 xml_node cc = dest.append_child(c.type()); 3054 assert(cc); 3055 3056 recursive_copy_skip(cc, c, skip); 3057 } 3058 3059 break; 3060 } 3061 3062 case node_pcdata: 3063 case node_cdata: 3064 case node_comment: 3065 case node_doctype: 3066 dest.set_value(source.value()); 3067 break; 3068 3069 case node_pi: 3070 dest.set_name(source.name()); 3071 dest.set_value(source.value()); 3072 break; 3073 3074 case node_declaration: 3075 { 3076 dest.set_name(source.name()); 3077 3078 for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute()) 3079 dest.append_attribute(a.name()).set_value(a.value()); 3080 3081 break; 3082 } 3083 3084 default: 3085 assert(!"Invalid node type"); 3086 } 4331 PUGI__FN bool allow_move(xml_node parent, xml_node child) 4332 { 4333 // check that child can be a child of parent 4334 if (!allow_insert_child(parent.type(), child.type())) 4335 return false; 4336 4337 // check that node is not moved between documents 4338 if (parent.root() != child.root()) 4339 return false; 4340 4341 // check that new parent is not in the child subtree 4342 xml_node cur = parent; 4343 4344 while (cur) 4345 { 4346 if (cur == child) 4347 return false; 4348 4349 cur = cur.parent(); 4350 } 4351 4352 return true; 4353 } 4354 4355 template <typename String, typename Header> 4356 PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc) 4357 { 4358 assert(!dest && (header & header_mask) == 0); 4359 4360 if (source) 4361 { 4362 if (alloc && (source_header & header_mask) == 0) 4363 { 4364 dest = source; 4365 4366 // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared 4367 header |= xml_memory_page_contents_shared_mask; 4368 source_header |= xml_memory_page_contents_shared_mask; 4369 } 4370 else 4371 strcpy_insitu(dest, header, header_mask, source, strlength(source)); 4372 } 4373 } 4374 4375 PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc) 4376 { 4377 node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc); 4378 node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc); 4379 4380 for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute) 4381 { 4382 xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn)); 4383 4384 if (da) 4385 { 4386 node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); 4387 node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); 4388 } 4389 } 4390 } 4391 4392 PUGI__FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn) 4393 { 4394 xml_allocator& alloc = get_allocator(dn); 4395 xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0; 4396 4397 node_copy_contents(dn, sn, shared_alloc); 4398 4399 xml_node_struct* dit = dn; 4400 xml_node_struct* sit = sn->first_child; 4401 4402 while (sit && sit != sn) 4403 { 4404 if (sit != dn) 4405 { 4406 xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit)); 4407 4408 if (copy) 4409 { 4410 node_copy_contents(copy, sit, shared_alloc); 4411 4412 if (sit->first_child) 4413 { 4414 dit = copy; 4415 sit = sit->first_child; 4416 continue; 4417 } 4418 } 4419 } 4420 4421 // continue to the next node 4422 do 4423 { 4424 if (sit->next_sibling) 4425 { 4426 sit = sit->next_sibling; 4427 break; 4428 } 4429 4430 sit = sit->parent; 4431 dit = dit->parent; 4432 } 4433 while (sit != sn); 4434 } 4435 } 4436 4437 PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa) 4438 { 4439 xml_allocator& alloc = get_allocator(da); 4440 xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0; 4441 4442 node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); 4443 node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); 4444 } 4445 4446 inline bool is_text_node(xml_node_struct* node) 4447 { 4448 xml_node_type type = PUGI__NODETYPE(node); 4449 4450 return type == node_pcdata || type == node_cdata; 4451 } 4452 4453 // get value with conversion functions 4454 template <typename U> U string_to_integer(const char_t* value, U minneg, U maxpos) 4455 { 4456 U result = 0; 4457 const char_t* s = value; 4458 4459 while (PUGI__IS_CHARTYPE(*s, ct_space)) 4460 s++; 4461 4462 bool negative = (*s == '-'); 4463 4464 s += (*s == '+' || *s == '-'); 4465 4466 bool overflow = false; 4467 4468 if (s[0] == '0' && (s[1] | ' ') == 'x') 4469 { 4470 s += 2; 4471 4472 // since overflow detection relies on length of the sequence skip leading zeros 4473 while (*s == '0') 4474 s++; 4475 4476 const char_t* start = s; 4477 4478 for (;;) 4479 { 4480 if (static_cast<unsigned>(*s - '0') < 10) 4481 result = result * 16 + (*s - '0'); 4482 else if (static_cast<unsigned>((*s | ' ') - 'a') < 6) 4483 result = result * 16 + ((*s | ' ') - 'a' + 10); 4484 else 4485 break; 4486 4487 s++; 4488 } 4489 4490 size_t digits = static_cast<size_t>(s - start); 4491 4492 overflow = digits > sizeof(U) * 2; 4493 } 4494 else 4495 { 4496 // since overflow detection relies on length of the sequence skip leading zeros 4497 while (*s == '0') 4498 s++; 4499 4500 const char_t* start = s; 4501 4502 for (;;) 4503 { 4504 if (static_cast<unsigned>(*s - '0') < 10) 4505 result = result * 10 + (*s - '0'); 4506 else 4507 break; 4508 4509 s++; 4510 } 4511 4512 size_t digits = static_cast<size_t>(s - start); 4513 4514 PUGI__STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2); 4515 4516 const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5; 4517 const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6'; 4518 const size_t high_bit = sizeof(U) * 8 - 1; 4519 4520 overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit))); 4521 } 4522 4523 if (negative) 4524 return (overflow || result > minneg) ? 0 - minneg : 0 - result; 4525 else 4526 return (overflow || result > maxpos) ? maxpos : result; 4527 } 4528 4529 PUGI__FN int get_value_int(const char_t* value) 4530 { 4531 return string_to_integer<unsigned int>(value, 0 - static_cast<unsigned int>(INT_MIN), INT_MAX); 4532 } 4533 4534 PUGI__FN unsigned int get_value_uint(const char_t* value) 4535 { 4536 return string_to_integer<unsigned int>(value, 0, UINT_MAX); 4537 } 4538 4539 PUGI__FN double get_value_double(const char_t* value) 4540 { 4541 #ifdef PUGIXML_WCHAR_MODE 4542 return wcstod(value, 0); 4543 #else 4544 return strtod(value, 0); 4545 #endif 4546 } 4547 4548 PUGI__FN float get_value_float(const char_t* value) 4549 { 4550 #ifdef PUGIXML_WCHAR_MODE 4551 return static_cast<float>(wcstod(value, 0)); 4552 #else 4553 return static_cast<float>(strtod(value, 0)); 4554 #endif 4555 } 4556 4557 PUGI__FN bool get_value_bool(const char_t* value) 4558 { 4559 // only look at first char 4560 char_t first = *value; 4561 4562 // 1*, t* (true), T* (True), y* (yes), Y* (YES) 4563 return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); 4564 } 4565 4566 #ifdef PUGIXML_HAS_LONG_LONG 4567 PUGI__FN long long get_value_llong(const char_t* value) 4568 { 4569 return string_to_integer<unsigned long long>(value, 0 - static_cast<unsigned long long>(LLONG_MIN), LLONG_MAX); 4570 } 4571 4572 PUGI__FN unsigned long long get_value_ullong(const char_t* value) 4573 { 4574 return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX); 4575 } 4576 #endif 4577 4578 template <typename U> PUGI__FN char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative) 4579 { 4580 char_t* result = end - 1; 4581 U rest = negative ? 0 - value : value; 4582 4583 do 4584 { 4585 *result-- = static_cast<char_t>('0' + (rest % 10)); 4586 rest /= 10; 4587 } 4588 while (rest); 4589 4590 assert(result >= begin); 4591 (void)begin; 4592 4593 *result = '-'; 4594 4595 return result + !negative; 4596 } 4597 4598 // set value with conversion functions 4599 template <typename String, typename Header> 4600 PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf) 4601 { 4602 #ifdef PUGIXML_WCHAR_MODE 4603 char_t wbuf[128]; 4604 assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0])); 4605 4606 size_t offset = 0; 4607 for (; buf[offset]; ++offset) wbuf[offset] = buf[offset]; 4608 4609 return strcpy_insitu(dest, header, header_mask, wbuf, offset); 4610 #else 4611 return strcpy_insitu(dest, header, header_mask, buf, strlen(buf)); 4612 #endif 4613 } 4614 4615 template <typename U, typename String, typename Header> 4616 PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative) 4617 { 4618 char_t buf[64]; 4619 char_t* end = buf + sizeof(buf) / sizeof(buf[0]); 4620 char_t* begin = integer_to_string(buf, end, value, negative); 4621 4622 return strcpy_insitu(dest, header, header_mask, begin, end - begin); 4623 } 4624 4625 template <typename String, typename Header> 4626 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value) 4627 { 4628 char buf[128]; 4629 sprintf(buf, "%.9g", value); 4630 4631 return set_value_ascii(dest, header, header_mask, buf); 4632 } 4633 4634 template <typename String, typename Header> 4635 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value) 4636 { 4637 char buf[128]; 4638 sprintf(buf, "%.17g", value); 4639 4640 return set_value_ascii(dest, header, header_mask, buf); 4641 } 4642 4643 template <typename String, typename Header> 4644 PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value) 4645 { 4646 return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); 4647 } 4648 4649 PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) 4650 { 4651 // check input buffer 4652 if (!contents && size) return make_parse_result(status_io_error); 4653 4654 // get actual encoding 4655 xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); 4656 4657 // get private buffer 4658 char_t* buffer = 0; 4659 size_t length = 0; 4660 4661 if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); 4662 4663 // delete original buffer if we performed a conversion 4664 if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); 4665 4666 // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself 4667 if (own || buffer != contents) *out_buffer = buffer; 4668 4669 // store buffer for offset_debug 4670 doc->buffer = buffer; 4671 4672 // parse 4673 xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options); 4674 4675 // remember encoding 4676 res.encoding = buffer_encoding; 4677 4678 return res; 3087 4679 } 3088 4680 3089 4681 // 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 3090 xml_parse_status get_file_size(FILE* file, size_t& out_result)3091 { 3092 #if defined( _MSC_VER) && _MSC_VER >= 14004682 PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result) 4683 { 4684 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) 3093 4685 // there are 64-bit versions of fseek/ftell, let's use them 3094 4686 typedef __int64 length_type; … … 3097 4689 length_type length = _ftelli64(file); 3098 4690 _fseeki64(file, 0, SEEK_SET); 3099 #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__)4691 #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)) 3100 4692 // there are 64-bit versions of fseek/ftell, let's use them 3101 4693 typedef off64_t length_type; … … 3115 4707 // check for I/O errors 3116 4708 if (length < 0) return status_io_error; 3117 4709 3118 4710 // check for overflow 3119 4711 size_t result = static_cast<size_t>(length); … … 3127 4719 } 3128 4720 3129 xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding) 4721 // This function assumes that buffer has extra sizeof(char_t) writable bytes after size 4722 PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) 4723 { 4724 // We only need to zero-terminate if encoding conversion does not do it for us 4725 #ifdef PUGIXML_WCHAR_MODE 4726 xml_encoding wchar_encoding = get_wchar_encoding(); 4727 4728 if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding)) 4729 { 4730 size_t length = size / sizeof(char_t); 4731 4732 static_cast<char_t*>(buffer)[length] = 0; 4733 return (length + 1) * sizeof(char_t); 4734 } 4735 #else 4736 if (encoding == encoding_utf8) 4737 { 4738 static_cast<char*>(buffer)[size] = 0; 4739 return size + 1; 4740 } 4741 #endif 4742 4743 return size; 4744 } 4745 4746 PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer) 3130 4747 { 3131 4748 if (!file) return make_parse_result(status_file_not_found); … … 3134 4751 size_t size = 0; 3135 4752 xml_parse_status size_status = get_file_size(file, size); 3136 3137 if (size_status != status_ok) 3138 { 3139 fclose(file); 3140 return make_parse_result(size_status); 3141 } 3142 4753 if (size_status != status_ok) return make_parse_result(size_status); 4754 4755 size_t max_suffix_size = sizeof(char_t); 4756 3143 4757 // allocate buffer for the whole file 3144 char* contents = static_cast<char*>(global_allocate(size > 0 ? size : 1)); 3145 3146 if (!contents) 3147 { 3148 fclose(file); 3149 return make_parse_result(status_out_of_memory); 3150 } 4758 char* contents = static_cast<char*>(xml_memory::allocate(size + max_suffix_size)); 4759 if (!contents) return make_parse_result(status_out_of_memory); 3151 4760 3152 4761 // read file in memory 3153 4762 size_t read_size = fread(contents, 1, size, file); 4763 4764 if (read_size != size) 4765 { 4766 xml_memory::deallocate(contents); 4767 return make_parse_result(status_io_error); 4768 } 4769 4770 xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size); 4771 4772 return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer); 4773 } 4774 4775 PUGI__FN void close_file(FILE* file) 4776 { 3154 4777 fclose(file); 3155 3156 if (read_size != size)3157 {3158 global_deallocate(contents);3159 return make_parse_result(status_io_error);3160 }3161 3162 return doc.load_buffer_inplace_own(contents, size, options, encoding);3163 4778 } 3164 4779 3165 4780 #ifndef PUGIXML_NO_STL 3166 template <typename T> xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding) 4781 template <typename T> struct xml_stream_chunk 4782 { 4783 static xml_stream_chunk* create() 4784 { 4785 void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); 4786 if (!memory) return 0; 4787 4788 return new (memory) xml_stream_chunk(); 4789 } 4790 4791 static void destroy(xml_stream_chunk* chunk) 4792 { 4793 // free chunk chain 4794 while (chunk) 4795 { 4796 xml_stream_chunk* next_ = chunk->next; 4797 4798 xml_memory::deallocate(chunk); 4799 4800 chunk = next_; 4801 } 4802 } 4803 4804 xml_stream_chunk(): next(0), size(0) 4805 { 4806 } 4807 4808 xml_stream_chunk* next; 4809 size_t size; 4810 4811 T data[xml_memory_page_size / sizeof(T)]; 4812 }; 4813 4814 template <typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size) 4815 { 4816 auto_deleter<xml_stream_chunk<T> > chunks(0, xml_stream_chunk<T>::destroy); 4817 4818 // read file to a chunk list 4819 size_t total = 0; 4820 xml_stream_chunk<T>* last = 0; 4821 4822 while (!stream.eof()) 4823 { 4824 // allocate new chunk 4825 xml_stream_chunk<T>* chunk = xml_stream_chunk<T>::create(); 4826 if (!chunk) return status_out_of_memory; 4827 4828 // append chunk to list 4829 if (last) last = last->next = chunk; 4830 else chunks.data = last = chunk; 4831 4832 // read data to chunk 4833 stream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T))); 4834 chunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T); 4835 4836 // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors 4837 if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; 4838 4839 // guard against huge files (chunk size is small enough to make this overflow check work) 4840 if (total + chunk->size < total) return status_out_of_memory; 4841 total += chunk->size; 4842 } 4843 4844 size_t max_suffix_size = sizeof(char_t); 4845 4846 // copy chunk list to a contiguous buffer 4847 char* buffer = static_cast<char*>(xml_memory::allocate(total + max_suffix_size)); 4848 if (!buffer) return status_out_of_memory; 4849 4850 char* write = buffer; 4851 4852 for (xml_stream_chunk<T>* chunk = chunks.data; chunk; chunk = chunk->next) 4853 { 4854 assert(write + chunk->size <= buffer + total); 4855 memcpy(write, chunk->data, chunk->size); 4856 write += chunk->size; 4857 } 4858 4859 assert(write == buffer + total); 4860 4861 // return buffer 4862 *out_buffer = buffer; 4863 *out_size = total; 4864 4865 return status_ok; 4866 } 4867 4868 template <typename T> PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size) 3167 4869 { 3168 4870 // get length of remaining data in stream … … 3172 4874 stream.seekg(pos); 3173 4875 3174 if (stream.fail() || pos < 0) return make_parse_result(status_io_error);4876 if (stream.fail() || pos < 0) return status_io_error; 3175 4877 3176 4878 // guard against huge files 3177 4879 size_t read_length = static_cast<size_t>(length); 3178 4880 3179 if (static_cast<std::streamsize>(read_length) != length || length < 0) return make_parse_result(status_out_of_memory); 4881 if (static_cast<std::streamsize>(read_length) != length || length < 0) return status_out_of_memory; 4882 4883 size_t max_suffix_size = sizeof(char_t); 3180 4884 3181 4885 // read stream data into memory (guard against stream exceptions with buffer holder) 3182 buffer_holder buffer(global_allocate((read_length > 0 ? read_length : 1) * sizeof(T)), global_deallocate);3183 if (!buffer.data) return make_parse_result(status_out_of_memory);4886 auto_deleter<void> buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate); 4887 if (!buffer.data) return status_out_of_memory; 3184 4888 3185 4889 stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length)); 3186 4890 3187 4891 // 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 3188 if (stream.bad() ) return make_parse_result(status_io_error);3189 3190 // load data frombuffer4892 if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; 4893 4894 // return buffer 3191 4895 size_t actual_length = static_cast<size_t>(stream.gcount()); 3192 4896 assert(actual_length <= read_length); 3193 4897 3194 return doc.load_buffer_inplace_own(buffer.release(), actual_length * sizeof(T), options, encoding); 4898 *out_buffer = buffer.release(); 4899 *out_size = actual_length * sizeof(T); 4900 4901 return status_ok; 4902 } 4903 4904 template <typename T> PUGI__FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding, char_t** out_buffer) 4905 { 4906 void* buffer = 0; 4907 size_t size = 0; 4908 xml_parse_status status = status_ok; 4909 4910 // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits) 4911 if (stream.fail()) return make_parse_result(status_io_error); 4912 4913 // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory) 4914 if (stream.tellg() < 0) 4915 { 4916 stream.clear(); // clear error flags that could be set by a failing tellg 4917 status = load_stream_data_noseek(stream, &buffer, &size); 4918 } 4919 else 4920 status = load_stream_data_seek(stream, &buffer, &size); 4921 4922 if (status != status_ok) return make_parse_result(status); 4923 4924 xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size); 4925 4926 return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer); 3195 4927 } 3196 4928 #endif 3197 4929 3198 #if defined( _MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)3199 FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)4930 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))) 4931 PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) 3200 4932 { 3201 4933 return _wfopen(path, mode); 3202 4934 } 3203 4935 #else 3204 char* convert_path_heap(const wchar_t* str)4936 PUGI__FN char* convert_path_heap(const wchar_t* str) 3205 4937 { 3206 4938 assert(str); 3207 4939 3208 4940 // first pass: get length in utf8 characters 3209 size_t length = wcslen(str);3210 4941 size_t length = strlength_wide(str); 4942 size_t size = as_utf8_begin(str, length); 3211 4943 3212 4944 // allocate resulting string 3213 char* result = static_cast<char*>( global_allocate(size + 1));4945 char* result = static_cast<char*>(xml_memory::allocate(size + 1)); 3214 4946 if (!result) return 0; 3215 4947 3216 4948 // second pass: convert to utf8 3217 as_utf8_end(result, size, str, length); 3218 3219 return result; 3220 } 3221 3222 FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) 4949 as_utf8_end(result, size, str, length); 4950 4951 // zero-terminate 4952 result[size] = 0; 4953 4954 return result; 4955 } 4956 4957 PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) 3223 4958 { 3224 4959 // there is no standard function to open wide paths, so our best bet is to try utf8 path … … 3234 4969 3235 4970 // free dummy buffer 3236 global_deallocate(path_utf8);4971 xml_memory::deallocate(path_utf8); 3237 4972 3238 4973 return result; 3239 4974 } 3240 4975 #endif 3241 } 4976 4977 PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding) 4978 { 4979 if (!file) return false; 4980 4981 xml_writer_file writer(file); 4982 doc.save(writer, indent, flags, encoding); 4983 4984 return ferror(file) == 0; 4985 } 4986 4987 struct name_null_sentry 4988 { 4989 xml_node_struct* node; 4990 char_t* name; 4991 4992 name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name) 4993 { 4994 node->name = 0; 4995 } 4996 4997 ~name_null_sentry() 4998 { 4999 node->name = name; 5000 } 5001 }; 5002 PUGI__NS_END 3242 5003 3243 5004 namespace pugi 3244 5005 { 3245 xml_writer_file::xml_writer_file(void* file): file(file) 3246 { 3247 } 3248 3249 void xml_writer_file::write(const void* data, size_t size) 3250 { 3251 fwrite(data, size, 1, static_cast<FILE*>(file)); 5006 PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_) 5007 { 5008 } 5009 5010 PUGI__FN void xml_writer_file::write(const void* data, size_t size) 5011 { 5012 size_t result = fwrite(data, 1, size, static_cast<FILE*>(file)); 5013 (void)!result; // unfortunately we can't do proper error handling here 3252 5014 } 3253 5015 3254 5016 #ifndef PUGIXML_NO_STL 3255 xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)3256 { 3257 } 3258 3259 xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)3260 { 3261 } 3262 3263 void xml_writer_stream::write(const void* data, size_t size)5017 PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0) 5018 { 5019 } 5020 5021 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) 5022 { 5023 } 5024 5025 PUGI__FN void xml_writer_stream::write(const void* data, size_t size) 3264 5026 { 3265 5027 if (narrow_stream) … … 3278 5040 #endif 3279 5041 3280 xml_tree_walker::xml_tree_walker(): _depth(0)3281 { 3282 } 3283 3284 xml_tree_walker::~xml_tree_walker()3285 { 3286 } 3287 3288 int xml_tree_walker::depth() const5042 PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) 5043 { 5044 } 5045 5046 PUGI__FN xml_tree_walker::~xml_tree_walker() 5047 { 5048 } 5049 5050 PUGI__FN int xml_tree_walker::depth() const 3289 5051 { 3290 5052 return _depth; 3291 5053 } 3292 5054 3293 bool xml_tree_walker::begin(xml_node&)5055 PUGI__FN bool xml_tree_walker::begin(xml_node&) 3294 5056 { 3295 5057 return true; 3296 5058 } 3297 5059 3298 bool xml_tree_walker::end(xml_node&)5060 PUGI__FN bool xml_tree_walker::end(xml_node&) 3299 5061 { 3300 5062 return true; 3301 5063 } 3302 5064 3303 xml_attribute::xml_attribute(): _attr(0) 3304 { 3305 } 3306 3307 xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) 3308 { 3309 } 3310 3311 xml_attribute::operator xml_attribute::unspecified_bool_type() const 3312 { 3313 return _attr ? &xml_attribute::_attr : 0; 3314 } 3315 3316 bool xml_attribute::operator!() const 3317 { 3318 return !_attr; 3319 } 3320 3321 bool xml_attribute::operator==(const xml_attribute& r) const 5065 PUGI__FN xml_attribute::xml_attribute(): _attr(0) 5066 { 5067 } 5068 5069 PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr) 5070 { 5071 } 5072 5073 PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***) 5074 { 5075 } 5076 5077 PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const 5078 { 5079 return _attr ? unspecified_bool_xml_attribute : 0; 5080 } 5081 5082 PUGI__FN bool xml_attribute::operator!() const 5083 { 5084 return !_attr; 5085 } 5086 5087 PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const 3322 5088 { 3323 5089 return (_attr == r._attr); 3324 5090 } 3325 3326 bool xml_attribute::operator!=(const xml_attribute& r) const5091 5092 PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const 3327 5093 { 3328 5094 return (_attr != r._attr); 3329 5095 } 3330 5096 3331 bool xml_attribute::operator<(const xml_attribute& r) const5097 PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const 3332 5098 { 3333 5099 return (_attr < r._attr); 3334 5100 } 3335 3336 bool xml_attribute::operator>(const xml_attribute& r) const5101 5102 PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const 3337 5103 { 3338 5104 return (_attr > r._attr); 3339 5105 } 3340 3341 bool xml_attribute::operator<=(const xml_attribute& r) const5106 5107 PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const 3342 5108 { 3343 5109 return (_attr <= r._attr); 3344 5110 } 3345 3346 bool xml_attribute::operator>=(const xml_attribute& r) const5111 5112 PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const 3347 5113 { 3348 5114 return (_attr >= r._attr); 3349 5115 } 3350 5116 3351 xml_attribute xml_attribute::next_attribute() const 3352 { 3353 return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); 3354 } 3355 3356 xml_attribute xml_attribute::previous_attribute() const 3357 { 3358 return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); 3359 } 3360 3361 int xml_attribute::as_int() const 3362 { 3363 if (!_attr || !_attr->value) return 0; 3364 3365 #ifdef PUGIXML_WCHAR_MODE 3366 return (int)wcstol(_attr->value, 0, 10); 3367 #else 3368 return (int)strtol(_attr->value, 0, 10); 3369 #endif 3370 } 3371 3372 unsigned int xml_attribute::as_uint() const 3373 { 3374 if (!_attr || !_attr->value) return 0; 3375 3376 #ifdef PUGIXML_WCHAR_MODE 3377 return (unsigned int)wcstoul(_attr->value, 0, 10); 3378 #else 3379 return (unsigned int)strtoul(_attr->value, 0, 10); 3380 #endif 3381 } 3382 3383 double xml_attribute::as_double() const 3384 { 3385 if (!_attr || !_attr->value) return 0; 3386 3387 #ifdef PUGIXML_WCHAR_MODE 3388 return wcstod(_attr->value, 0); 3389 #else 3390 return strtod(_attr->value, 0); 3391 #endif 3392 } 3393 3394 float xml_attribute::as_float() const 3395 { 3396 if (!_attr || !_attr->value) return 0; 3397 3398 #ifdef PUGIXML_WCHAR_MODE 3399 return (float)wcstod(_attr->value, 0); 3400 #else 3401 return (float)strtod(_attr->value, 0); 3402 #endif 3403 } 3404 3405 bool xml_attribute::as_bool() const 3406 { 3407 if (!_attr || !_attr->value) return false; 3408 3409 // only look at first char 3410 char_t first = *_attr->value; 3411 3412 // 1*, t* (true), T* (True), y* (yes), Y* (YES) 3413 return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y'); 3414 } 3415 3416 bool xml_attribute::empty() const 5117 PUGI__FN xml_attribute xml_attribute::next_attribute() const 5118 { 5119 return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); 5120 } 5121 5122 PUGI__FN xml_attribute xml_attribute::previous_attribute() const 5123 { 5124 return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); 5125 } 5126 5127 PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const 5128 { 5129 return (_attr && _attr->value) ? _attr->value + 0 : def; 5130 } 5131 5132 PUGI__FN int xml_attribute::as_int(int def) const 5133 { 5134 return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def; 5135 } 5136 5137 PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const 5138 { 5139 return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def; 5140 } 5141 5142 PUGI__FN double xml_attribute::as_double(double def) const 5143 { 5144 return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def; 5145 } 5146 5147 PUGI__FN float xml_attribute::as_float(float def) const 5148 { 5149 return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def; 5150 } 5151 5152 PUGI__FN bool xml_attribute::as_bool(bool def) const 5153 { 5154 return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def; 5155 } 5156 5157 #ifdef PUGIXML_HAS_LONG_LONG 5158 PUGI__FN long long xml_attribute::as_llong(long long def) const 5159 { 5160 return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def; 5161 } 5162 5163 PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const 5164 { 5165 return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def; 5166 } 5167 #endif 5168 5169 PUGI__FN bool xml_attribute::empty() const 3417 5170 { 3418 5171 return !_attr; 3419 5172 } 3420 5173 3421 const char_t* xml_attribute::name() const3422 { 3423 return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT("");3424 } 3425 3426 const char_t* xml_attribute::value() const3427 { 3428 return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT("");3429 } 3430 3431 3432 3433 3434 3435 3436 xml_attribute_struct* xml_attribute::internal_object() const3437 { 3438 3439 } 3440 3441 xml_attribute& xml_attribute::operator=(const char_t* rhs)5174 PUGI__FN const char_t* xml_attribute::name() const 5175 { 5176 return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT(""); 5177 } 5178 5179 PUGI__FN const char_t* xml_attribute::value() const 5180 { 5181 return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT(""); 5182 } 5183 5184 PUGI__FN size_t xml_attribute::hash_value() const 5185 { 5186 return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct)); 5187 } 5188 5189 PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const 5190 { 5191 return _attr; 5192 } 5193 5194 PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) 3442 5195 { 3443 5196 set_value(rhs); 3444 5197 return *this; 3445 5198 } 3446 3447 xml_attribute& xml_attribute::operator=(int rhs)5199 5200 PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) 3448 5201 { 3449 5202 set_value(rhs); … … 3451 5204 } 3452 5205 3453 xml_attribute& xml_attribute::operator=(unsigned int rhs)5206 PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs) 3454 5207 { 3455 5208 set_value(rhs); … … 3457 5210 } 3458 5211 3459 xml_attribute& xml_attribute::operator=(doublerhs)5212 PUGI__FN xml_attribute& xml_attribute::operator=(long rhs) 3460 5213 { 3461 5214 set_value(rhs); 3462 5215 return *this; 3463 5216 } 3464 3465 xml_attribute& xml_attribute::operator=(boolrhs)5217 5218 PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long rhs) 3466 5219 { 3467 5220 set_value(rhs); … … 3469 5222 } 3470 5223 3471 bool xml_attribute::set_name(const char_t* rhs) 5224 PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) 5225 { 5226 set_value(rhs); 5227 return *this; 5228 } 5229 5230 PUGI__FN xml_attribute& xml_attribute::operator=(float rhs) 5231 { 5232 set_value(rhs); 5233 return *this; 5234 } 5235 5236 PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) 5237 { 5238 set_value(rhs); 5239 return *this; 5240 } 5241 5242 #ifdef PUGIXML_HAS_LONG_LONG 5243 PUGI__FN xml_attribute& xml_attribute::operator=(long long rhs) 5244 { 5245 set_value(rhs); 5246 return *this; 5247 } 5248 5249 PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long long rhs) 5250 { 5251 set_value(rhs); 5252 return *this; 5253 } 5254 #endif 5255 5256 PUGI__FN bool xml_attribute::set_name(const char_t* rhs) 3472 5257 { 3473 5258 if (!_attr) return false; 3474 3475 return strcpy_insitu(_attr->name, _attr->header, xml_memory_page_name_allocated_mask, rhs);3476 } 3477 3478 bool xml_attribute::set_value(const char_t* rhs)5259 5260 return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); 5261 } 5262 5263 PUGI__FN bool xml_attribute::set_value(const char_t* rhs) 3479 5264 { 3480 5265 if (!_attr) return false; 3481 5266 3482 return strcpy_insitu(_attr->value, _attr->header, xml_memory_page_value_allocated_mask, rhs); 3483 } 3484 3485 bool xml_attribute::set_value(int rhs) 3486 { 3487 char buf[128]; 3488 sprintf(buf, "%d", rhs); 3489 3490 #ifdef PUGIXML_WCHAR_MODE 3491 char_t wbuf[128]; 3492 widen_ascii(wbuf, buf); 3493 3494 return set_value(wbuf); 3495 #else 3496 return set_value(buf); 3497 #endif 3498 } 3499 3500 bool xml_attribute::set_value(unsigned int rhs) 3501 { 3502 char buf[128]; 3503 sprintf(buf, "%u", rhs); 3504 3505 #ifdef PUGIXML_WCHAR_MODE 3506 char_t wbuf[128]; 3507 widen_ascii(wbuf, buf); 3508 3509 return set_value(wbuf); 3510 #else 3511 return set_value(buf); 3512 #endif 3513 } 3514 3515 bool xml_attribute::set_value(double rhs) 3516 { 3517 char buf[128]; 3518 sprintf(buf, "%g", rhs); 3519 3520 #ifdef PUGIXML_WCHAR_MODE 3521 char_t wbuf[128]; 3522 widen_ascii(wbuf, buf); 3523 3524 return set_value(wbuf); 3525 #else 3526 return set_value(buf); 3527 #endif 3528 } 3529 3530 bool xml_attribute::set_value(bool rhs) 3531 { 3532 return set_value(rhs ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); 3533 } 5267 return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); 5268 } 5269 5270 PUGI__FN bool xml_attribute::set_value(int rhs) 5271 { 5272 if (!_attr) return false; 5273 5274 return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); 5275 } 5276 5277 PUGI__FN bool xml_attribute::set_value(unsigned int rhs) 5278 { 5279 if (!_attr) return false; 5280 5281 return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); 5282 } 5283 5284 PUGI__FN bool xml_attribute::set_value(long rhs) 5285 { 5286 if (!_attr) return false; 5287 5288 return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); 5289 } 5290 5291 PUGI__FN bool xml_attribute::set_value(unsigned long rhs) 5292 { 5293 if (!_attr) return false; 5294 5295 return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); 5296 } 5297 5298 PUGI__FN bool xml_attribute::set_value(double rhs) 5299 { 5300 if (!_attr) return false; 5301 5302 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); 5303 } 5304 5305 PUGI__FN bool xml_attribute::set_value(float rhs) 5306 { 5307 if (!_attr) return false; 5308 5309 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); 5310 } 5311 5312 PUGI__FN bool xml_attribute::set_value(bool rhs) 5313 { 5314 if (!_attr) return false; 5315 5316 return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); 5317 } 5318 5319 #ifdef PUGIXML_HAS_LONG_LONG 5320 PUGI__FN bool xml_attribute::set_value(long long rhs) 5321 { 5322 if (!_attr) return false; 5323 5324 return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); 5325 } 5326 5327 PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) 5328 { 5329 if (!_attr) return false; 5330 5331 return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); 5332 } 5333 #endif 3534 5334 3535 5335 #ifdef __BORLANDC__ 3536 bool operator&&(const xml_attribute& lhs, bool rhs)5336 PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs) 3537 5337 { 3538 5338 return (bool)lhs && rhs; 3539 5339 } 3540 5340 3541 bool operator||(const xml_attribute& lhs, bool rhs)5341 PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs) 3542 5342 { 3543 5343 return (bool)lhs || rhs; … … 3545 5345 #endif 3546 5346 3547 xml_node::xml_node(): _root(0) 3548 { 3549 } 3550 3551 xml_node::xml_node(xml_node_struct* p): _root(p) 3552 { 3553 } 3554 3555 xml_node::operator xml_node::unspecified_bool_type() const 3556 { 3557 return _root ? &xml_node::_root : 0; 3558 } 3559 3560 bool xml_node::operator!() const 3561 { 3562 return !_root; 3563 } 3564 3565 xml_node::iterator xml_node::begin() const 3566 { 3567 return iterator(_root ? _root->first_child : 0, _root); 3568 } 3569 3570 xml_node::iterator xml_node::end() const 5347 PUGI__FN xml_node::xml_node(): _root(0) 5348 { 5349 } 5350 5351 PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) 5352 { 5353 } 5354 5355 PUGI__FN static void unspecified_bool_xml_node(xml_node***) 5356 { 5357 } 5358 5359 PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const 5360 { 5361 return _root ? unspecified_bool_xml_node : 0; 5362 } 5363 5364 PUGI__FN bool xml_node::operator!() const 5365 { 5366 return !_root; 5367 } 5368 5369 PUGI__FN xml_node::iterator xml_node::begin() const 5370 { 5371 return iterator(_root ? _root->first_child + 0 : 0, _root); 5372 } 5373 5374 PUGI__FN xml_node::iterator xml_node::end() const 3571 5375 { 3572 5376 return iterator(0, _root); 3573 5377 } 3574 3575 xml_node::attribute_iterator xml_node::attributes_begin() const3576 { 3577 return attribute_iterator(_root ? _root->first_attribute : 0, _root);3578 } 3579 3580 xml_node::attribute_iterator xml_node::attributes_end() const5378 5379 PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const 5380 { 5381 return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root); 5382 } 5383 5384 PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const 3581 5385 { 3582 5386 return attribute_iterator(0, _root); 3583 5387 } 3584 5388 3585 bool xml_node::operator==(const xml_node& r) const 5389 PUGI__FN xml_object_range<xml_node_iterator> xml_node::children() const 5390 { 5391 return xml_object_range<xml_node_iterator>(begin(), end()); 5392 } 5393 5394 PUGI__FN xml_object_range<xml_named_node_iterator> xml_node::children(const char_t* name_) const 5395 { 5396 return xml_object_range<xml_named_node_iterator>(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_)); 5397 } 5398 5399 PUGI__FN xml_object_range<xml_attribute_iterator> xml_node::attributes() const 5400 { 5401 return xml_object_range<xml_attribute_iterator>(attributes_begin(), attributes_end()); 5402 } 5403 5404 PUGI__FN bool xml_node::operator==(const xml_node& r) const 3586 5405 { 3587 5406 return (_root == r._root); 3588 5407 } 3589 5408 3590 bool xml_node::operator!=(const xml_node& r) const5409 PUGI__FN bool xml_node::operator!=(const xml_node& r) const 3591 5410 { 3592 5411 return (_root != r._root); 3593 5412 } 3594 5413 3595 bool xml_node::operator<(const xml_node& r) const5414 PUGI__FN bool xml_node::operator<(const xml_node& r) const 3596 5415 { 3597 5416 return (_root < r._root); 3598 5417 } 3599 3600 bool xml_node::operator>(const xml_node& r) const5418 5419 PUGI__FN bool xml_node::operator>(const xml_node& r) const 3601 5420 { 3602 5421 return (_root > r._root); 3603 5422 } 3604 3605 bool xml_node::operator<=(const xml_node& r) const5423 5424 PUGI__FN bool xml_node::operator<=(const xml_node& r) const 3606 5425 { 3607 5426 return (_root <= r._root); 3608 5427 } 3609 3610 bool xml_node::operator>=(const xml_node& r) const5428 5429 PUGI__FN bool xml_node::operator>=(const xml_node& r) const 3611 5430 { 3612 5431 return (_root >= r._root); 3613 5432 } 3614 5433 3615 bool xml_node::empty() const5434 PUGI__FN bool xml_node::empty() const 3616 5435 { 3617 5436 return !_root; 3618 5437 } 3619 3620 const char_t* xml_node::name() const3621 { 3622 return (_root && _root->name) ? _root->name : PUGIXML_TEXT("");3623 } 3624 3625 xml_node_type xml_node::type() const3626 { 3627 return _root ? static_cast<xml_node_type>((_root->header & xml_memory_page_type_mask) + 1) : node_null;3628 } 3629 3630 const char_t* xml_node::value() const3631 { 3632 return (_root && _root->value) ? _root->value : PUGIXML_TEXT("");3633 } 3634 3635 xml_node xml_node::child(const char_t* name) const5438 5439 PUGI__FN const char_t* xml_node::name() const 5440 { 5441 return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(""); 5442 } 5443 5444 PUGI__FN xml_node_type xml_node::type() const 5445 { 5446 return _root ? PUGI__NODETYPE(_root) : node_null; 5447 } 5448 5449 PUGI__FN const char_t* xml_node::value() const 5450 { 5451 return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(""); 5452 } 5453 5454 PUGI__FN xml_node xml_node::child(const char_t* name_) const 3636 5455 { 3637 5456 if (!_root) return xml_node(); 3638 5457 3639 5458 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) 3640 if (i->name && strequal(name, i->name)) return xml_node(i);5459 if (i->name && impl::strequal(name_, i->name)) return xml_node(i); 3641 5460 3642 5461 return xml_node(); 3643 5462 } 3644 5463 3645 xml_attribute xml_node::attribute(const char_t* name) const5464 PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const 3646 5465 { 3647 5466 if (!_root) return xml_attribute(); 3648 5467 3649 5468 for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) 3650 if (i->name && strequal(name, i->name))5469 if (i->name && impl::strequal(name_, i->name)) 3651 5470 return xml_attribute(i); 3652 5471 3653 5472 return xml_attribute(); 3654 5473 } 3655 3656 xml_node xml_node::next_sibling(const char_t* name) const5474 5475 PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const 3657 5476 { 3658 5477 if (!_root) return xml_node(); 3659 5478 3660 5479 for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) 3661 if (i->name && strequal(name, i->name)) return xml_node(i);5480 if (i->name && impl::strequal(name_, i->name)) return xml_node(i); 3662 5481 3663 5482 return xml_node(); 3664 5483 } 3665 5484 3666 xml_node xml_node::next_sibling() const 5485 PUGI__FN xml_node xml_node::next_sibling() const 5486 { 5487 return _root ? xml_node(_root->next_sibling) : xml_node(); 5488 } 5489 5490 PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const 3667 5491 { 3668 5492 if (!_root) return xml_node(); 3669 3670 if (_root->next_sibling) return xml_node(_root->next_sibling); 3671 else return xml_node(); 3672 } 3673 3674 xml_node xml_node::previous_sibling(const char_t* name) const 5493 5494 for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) 5495 if (i->name && impl::strequal(name_, i->name)) return xml_node(i); 5496 5497 return xml_node(); 5498 } 5499 5500 PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const 5501 { 5502 xml_attribute_struct* hint = hint_._attr; 5503 5504 // if hint is not an attribute of node, behavior is not defined 5505 assert(!hint || (_root && impl::is_attribute_of(hint, _root))); 5506 5507 if (!_root) return xml_attribute(); 5508 5509 // optimistically search from hint up until the end 5510 for (xml_attribute_struct* i = hint; i; i = i->next_attribute) 5511 if (i->name && impl::strequal(name_, i->name)) 5512 { 5513 // update hint to maximize efficiency of searching for consecutive attributes 5514 hint_._attr = i->next_attribute; 5515 5516 return xml_attribute(i); 5517 } 5518 5519 // wrap around and search from the first attribute until the hint 5520 // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails 5521 for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute) 5522 if (j->name && impl::strequal(name_, j->name)) 5523 { 5524 // update hint to maximize efficiency of searching for consecutive attributes 5525 hint_._attr = j->next_attribute; 5526 5527 return xml_attribute(j); 5528 } 5529 5530 return xml_attribute(); 5531 } 5532 5533 PUGI__FN xml_node xml_node::previous_sibling() const 3675 5534 { 3676 5535 if (!_root) return xml_node(); 3677 3678 for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) 3679 if (i->name && strequal(name, i->name)) return xml_node(i); 3680 3681 return xml_node(); 3682 } 3683 3684 xml_node xml_node::previous_sibling() const 3685 { 3686 if (!_root) return xml_node(); 3687 5536 3688 5537 if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); 3689 5538 else return xml_node(); 3690 5539 } 3691 5540 3692 xml_node xml_node::parent() const5541 PUGI__FN xml_node xml_node::parent() const 3693 5542 { 3694 5543 return _root ? xml_node(_root->parent) : xml_node(); 3695 5544 } 3696 5545 3697 xml_node xml_node::root() const 5546 PUGI__FN xml_node xml_node::root() const 5547 { 5548 return _root ? xml_node(&impl::get_document(_root)) : xml_node(); 5549 } 5550 5551 PUGI__FN xml_text xml_node::text() const 5552 { 5553 return xml_text(_root); 5554 } 5555 5556 PUGI__FN const char_t* xml_node::child_value() const 5557 { 5558 if (!_root) return PUGIXML_TEXT(""); 5559 5560 // element nodes can have value if parse_embed_pcdata was used 5561 if (PUGI__NODETYPE(_root) == node_element && _root->value) 5562 return _root->value; 5563 5564 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) 5565 if (impl::is_text_node(i) && i->value) 5566 return i->value; 5567 5568 return PUGIXML_TEXT(""); 5569 } 5570 5571 PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const 5572 { 5573 return child(name_).child_value(); 5574 } 5575 5576 PUGI__FN xml_attribute xml_node::first_attribute() const 5577 { 5578 return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); 5579 } 5580 5581 PUGI__FN xml_attribute xml_node::last_attribute() const 5582 { 5583 return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); 5584 } 5585 5586 PUGI__FN xml_node xml_node::first_child() const 5587 { 5588 return _root ? xml_node(_root->first_child) : xml_node(); 5589 } 5590 5591 PUGI__FN xml_node xml_node::last_child() const 5592 { 5593 return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); 5594 } 5595 5596 PUGI__FN bool xml_node::set_name(const char_t* rhs) 5597 { 5598 xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; 5599 5600 if (type_ != node_element && type_ != node_pi && type_ != node_declaration) 5601 return false; 5602 5603 return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); 5604 } 5605 5606 PUGI__FN bool xml_node::set_value(const char_t* rhs) 5607 { 5608 xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; 5609 5610 if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) 5611 return false; 5612 5613 return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); 5614 } 5615 5616 PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) 5617 { 5618 if (!impl::allow_insert_attribute(type())) return xml_attribute(); 5619 5620 impl::xml_allocator& alloc = impl::get_allocator(_root); 5621 if (!alloc.reserve()) return xml_attribute(); 5622 5623 xml_attribute a(impl::allocate_attribute(alloc)); 5624 if (!a) return xml_attribute(); 5625 5626 impl::append_attribute(a._attr, _root); 5627 5628 a.set_name(name_); 5629 5630 return a; 5631 } 5632 5633 PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) 5634 { 5635 if (!impl::allow_insert_attribute(type())) return xml_attribute(); 5636 5637 impl::xml_allocator& alloc = impl::get_allocator(_root); 5638 if (!alloc.reserve()) return xml_attribute(); 5639 5640 xml_attribute a(impl::allocate_attribute(alloc)); 5641 if (!a) return xml_attribute(); 5642 5643 impl::prepend_attribute(a._attr, _root); 5644 5645 a.set_name(name_); 5646 5647 return a; 5648 } 5649 5650 PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) 5651 { 5652 if (!impl::allow_insert_attribute(type())) return xml_attribute(); 5653 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); 5654 5655 impl::xml_allocator& alloc = impl::get_allocator(_root); 5656 if (!alloc.reserve()) return xml_attribute(); 5657 5658 xml_attribute a(impl::allocate_attribute(alloc)); 5659 if (!a) return xml_attribute(); 5660 5661 impl::insert_attribute_after(a._attr, attr._attr, _root); 5662 5663 a.set_name(name_); 5664 5665 return a; 5666 } 5667 5668 PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) 5669 { 5670 if (!impl::allow_insert_attribute(type())) return xml_attribute(); 5671 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); 5672 5673 impl::xml_allocator& alloc = impl::get_allocator(_root); 5674 if (!alloc.reserve()) return xml_attribute(); 5675 5676 xml_attribute a(impl::allocate_attribute(alloc)); 5677 if (!a) return xml_attribute(); 5678 5679 impl::insert_attribute_before(a._attr, attr._attr, _root); 5680 5681 a.set_name(name_); 5682 5683 return a; 5684 } 5685 5686 PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto) 5687 { 5688 if (!proto) return xml_attribute(); 5689 if (!impl::allow_insert_attribute(type())) return xml_attribute(); 5690 5691 impl::xml_allocator& alloc = impl::get_allocator(_root); 5692 if (!alloc.reserve()) return xml_attribute(); 5693 5694 xml_attribute a(impl::allocate_attribute(alloc)); 5695 if (!a) return xml_attribute(); 5696 5697 impl::append_attribute(a._attr, _root); 5698 impl::node_copy_attribute(a._attr, proto._attr); 5699 5700 return a; 5701 } 5702 5703 PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto) 5704 { 5705 if (!proto) return xml_attribute(); 5706 if (!impl::allow_insert_attribute(type())) return xml_attribute(); 5707 5708 impl::xml_allocator& alloc = impl::get_allocator(_root); 5709 if (!alloc.reserve()) return xml_attribute(); 5710 5711 xml_attribute a(impl::allocate_attribute(alloc)); 5712 if (!a) return xml_attribute(); 5713 5714 impl::prepend_attribute(a._attr, _root); 5715 impl::node_copy_attribute(a._attr, proto._attr); 5716 5717 return a; 5718 } 5719 5720 PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) 5721 { 5722 if (!proto) return xml_attribute(); 5723 if (!impl::allow_insert_attribute(type())) return xml_attribute(); 5724 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); 5725 5726 impl::xml_allocator& alloc = impl::get_allocator(_root); 5727 if (!alloc.reserve()) return xml_attribute(); 5728 5729 xml_attribute a(impl::allocate_attribute(alloc)); 5730 if (!a) return xml_attribute(); 5731 5732 impl::insert_attribute_after(a._attr, attr._attr, _root); 5733 impl::node_copy_attribute(a._attr, proto._attr); 5734 5735 return a; 5736 } 5737 5738 PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) 5739 { 5740 if (!proto) return xml_attribute(); 5741 if (!impl::allow_insert_attribute(type())) return xml_attribute(); 5742 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); 5743 5744 impl::xml_allocator& alloc = impl::get_allocator(_root); 5745 if (!alloc.reserve()) return xml_attribute(); 5746 5747 xml_attribute a(impl::allocate_attribute(alloc)); 5748 if (!a) return xml_attribute(); 5749 5750 impl::insert_attribute_before(a._attr, attr._attr, _root); 5751 impl::node_copy_attribute(a._attr, proto._attr); 5752 5753 return a; 5754 } 5755 5756 PUGI__FN xml_node xml_node::append_child(xml_node_type type_) 5757 { 5758 if (!impl::allow_insert_child(type(), type_)) return xml_node(); 5759 5760 impl::xml_allocator& alloc = impl::get_allocator(_root); 5761 if (!alloc.reserve()) return xml_node(); 5762 5763 xml_node n(impl::allocate_node(alloc, type_)); 5764 if (!n) return xml_node(); 5765 5766 impl::append_node(n._root, _root); 5767 5768 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); 5769 5770 return n; 5771 } 5772 5773 PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_) 5774 { 5775 if (!impl::allow_insert_child(type(), type_)) return xml_node(); 5776 5777 impl::xml_allocator& alloc = impl::get_allocator(_root); 5778 if (!alloc.reserve()) return xml_node(); 5779 5780 xml_node n(impl::allocate_node(alloc, type_)); 5781 if (!n) return xml_node(); 5782 5783 impl::prepend_node(n._root, _root); 5784 5785 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); 5786 5787 return n; 5788 } 5789 5790 PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node) 5791 { 5792 if (!impl::allow_insert_child(type(), type_)) return xml_node(); 5793 if (!node._root || node._root->parent != _root) return xml_node(); 5794 5795 impl::xml_allocator& alloc = impl::get_allocator(_root); 5796 if (!alloc.reserve()) return xml_node(); 5797 5798 xml_node n(impl::allocate_node(alloc, type_)); 5799 if (!n) return xml_node(); 5800 5801 impl::insert_node_before(n._root, node._root); 5802 5803 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); 5804 5805 return n; 5806 } 5807 5808 PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node) 5809 { 5810 if (!impl::allow_insert_child(type(), type_)) return xml_node(); 5811 if (!node._root || node._root->parent != _root) return xml_node(); 5812 5813 impl::xml_allocator& alloc = impl::get_allocator(_root); 5814 if (!alloc.reserve()) return xml_node(); 5815 5816 xml_node n(impl::allocate_node(alloc, type_)); 5817 if (!n) return xml_node(); 5818 5819 impl::insert_node_after(n._root, node._root); 5820 5821 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); 5822 5823 return n; 5824 } 5825 5826 PUGI__FN xml_node xml_node::append_child(const char_t* name_) 5827 { 5828 xml_node result = append_child(node_element); 5829 5830 result.set_name(name_); 5831 5832 return result; 5833 } 5834 5835 PUGI__FN xml_node xml_node::prepend_child(const char_t* name_) 5836 { 5837 xml_node result = prepend_child(node_element); 5838 5839 result.set_name(name_); 5840 5841 return result; 5842 } 5843 5844 PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) 5845 { 5846 xml_node result = insert_child_after(node_element, node); 5847 5848 result.set_name(name_); 5849 5850 return result; 5851 } 5852 5853 PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) 5854 { 5855 xml_node result = insert_child_before(node_element, node); 5856 5857 result.set_name(name_); 5858 5859 return result; 5860 } 5861 5862 PUGI__FN xml_node xml_node::append_copy(const xml_node& proto) 5863 { 5864 xml_node_type type_ = proto.type(); 5865 if (!impl::allow_insert_child(type(), type_)) return xml_node(); 5866 5867 impl::xml_allocator& alloc = impl::get_allocator(_root); 5868 if (!alloc.reserve()) return xml_node(); 5869 5870 xml_node n(impl::allocate_node(alloc, type_)); 5871 if (!n) return xml_node(); 5872 5873 impl::append_node(n._root, _root); 5874 impl::node_copy_tree(n._root, proto._root); 5875 5876 return n; 5877 } 5878 5879 PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto) 5880 { 5881 xml_node_type type_ = proto.type(); 5882 if (!impl::allow_insert_child(type(), type_)) return xml_node(); 5883 5884 impl::xml_allocator& alloc = impl::get_allocator(_root); 5885 if (!alloc.reserve()) return xml_node(); 5886 5887 xml_node n(impl::allocate_node(alloc, type_)); 5888 if (!n) return xml_node(); 5889 5890 impl::prepend_node(n._root, _root); 5891 impl::node_copy_tree(n._root, proto._root); 5892 5893 return n; 5894 } 5895 5896 PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) 5897 { 5898 xml_node_type type_ = proto.type(); 5899 if (!impl::allow_insert_child(type(), type_)) return xml_node(); 5900 if (!node._root || node._root->parent != _root) return xml_node(); 5901 5902 impl::xml_allocator& alloc = impl::get_allocator(_root); 5903 if (!alloc.reserve()) return xml_node(); 5904 5905 xml_node n(impl::allocate_node(alloc, type_)); 5906 if (!n) return xml_node(); 5907 5908 impl::insert_node_after(n._root, node._root); 5909 impl::node_copy_tree(n._root, proto._root); 5910 5911 return n; 5912 } 5913 5914 PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) 5915 { 5916 xml_node_type type_ = proto.type(); 5917 if (!impl::allow_insert_child(type(), type_)) return xml_node(); 5918 if (!node._root || node._root->parent != _root) return xml_node(); 5919 5920 impl::xml_allocator& alloc = impl::get_allocator(_root); 5921 if (!alloc.reserve()) return xml_node(); 5922 5923 xml_node n(impl::allocate_node(alloc, type_)); 5924 if (!n) return xml_node(); 5925 5926 impl::insert_node_before(n._root, node._root); 5927 impl::node_copy_tree(n._root, proto._root); 5928 5929 return n; 5930 } 5931 5932 PUGI__FN xml_node xml_node::append_move(const xml_node& moved) 5933 { 5934 if (!impl::allow_move(*this, moved)) return xml_node(); 5935 5936 impl::xml_allocator& alloc = impl::get_allocator(_root); 5937 if (!alloc.reserve()) return xml_node(); 5938 5939 // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers 5940 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; 5941 5942 impl::remove_node(moved._root); 5943 impl::append_node(moved._root, _root); 5944 5945 return moved; 5946 } 5947 5948 PUGI__FN xml_node xml_node::prepend_move(const xml_node& moved) 5949 { 5950 if (!impl::allow_move(*this, moved)) return xml_node(); 5951 5952 impl::xml_allocator& alloc = impl::get_allocator(_root); 5953 if (!alloc.reserve()) return xml_node(); 5954 5955 // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers 5956 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; 5957 5958 impl::remove_node(moved._root); 5959 impl::prepend_node(moved._root, _root); 5960 5961 return moved; 5962 } 5963 5964 PUGI__FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node) 5965 { 5966 if (!impl::allow_move(*this, moved)) return xml_node(); 5967 if (!node._root || node._root->parent != _root) return xml_node(); 5968 if (moved._root == node._root) return xml_node(); 5969 5970 impl::xml_allocator& alloc = impl::get_allocator(_root); 5971 if (!alloc.reserve()) return xml_node(); 5972 5973 // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers 5974 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; 5975 5976 impl::remove_node(moved._root); 5977 impl::insert_node_after(moved._root, node._root); 5978 5979 return moved; 5980 } 5981 5982 PUGI__FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node) 5983 { 5984 if (!impl::allow_move(*this, moved)) return xml_node(); 5985 if (!node._root || node._root->parent != _root) return xml_node(); 5986 if (moved._root == node._root) return xml_node(); 5987 5988 impl::xml_allocator& alloc = impl::get_allocator(_root); 5989 if (!alloc.reserve()) return xml_node(); 5990 5991 // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers 5992 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask; 5993 5994 impl::remove_node(moved._root); 5995 impl::insert_node_before(moved._root, node._root); 5996 5997 return moved; 5998 } 5999 6000 PUGI__FN bool xml_node::remove_attribute(const char_t* name_) 6001 { 6002 return remove_attribute(attribute(name_)); 6003 } 6004 6005 PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a) 6006 { 6007 if (!_root || !a._attr) return false; 6008 if (!impl::is_attribute_of(a._attr, _root)) return false; 6009 6010 impl::xml_allocator& alloc = impl::get_allocator(_root); 6011 if (!alloc.reserve()) return false; 6012 6013 impl::remove_attribute(a._attr, _root); 6014 impl::destroy_attribute(a._attr, alloc); 6015 6016 return true; 6017 } 6018 6019 PUGI__FN bool xml_node::remove_child(const char_t* name_) 6020 { 6021 return remove_child(child(name_)); 6022 } 6023 6024 PUGI__FN bool xml_node::remove_child(const xml_node& n) 6025 { 6026 if (!_root || !n._root || n._root->parent != _root) return false; 6027 6028 impl::xml_allocator& alloc = impl::get_allocator(_root); 6029 if (!alloc.reserve()) return false; 6030 6031 impl::remove_node(n._root); 6032 impl::destroy_node(n._root, alloc); 6033 6034 return true; 6035 } 6036 6037 PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) 6038 { 6039 // append_buffer is only valid for elements/documents 6040 if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root); 6041 6042 // get document node 6043 impl::xml_document_struct* doc = &impl::get_document(_root); 6044 6045 // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense 6046 doc->header |= impl::xml_memory_page_contents_shared_mask; 6047 6048 // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later) 6049 impl::xml_memory_page* page = 0; 6050 impl::xml_extra_buffer* extra = static_cast<impl::xml_extra_buffer*>(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page)); 6051 (void)page; 6052 6053 if (!extra) return impl::make_parse_result(status_out_of_memory); 6054 6055 // add extra buffer to the list 6056 extra->buffer = 0; 6057 extra->next = doc->extra_buffers; 6058 doc->extra_buffers = extra; 6059 6060 // name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level 6061 impl::name_null_sentry sentry(_root); 6062 6063 return impl::load_buffer_impl(doc, _root, const_cast<void*>(contents), size, options, encoding, false, false, &extra->buffer); 6064 } 6065 6066 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 3698 6067 { 3699 6068 if (!_root) return xml_node(); 3700 6069 3701 xml_memory_page* page = reinterpret_cast<xml_memory_page*>(_root->header & xml_memory_page_pointer_mask);3702 3703 return xml_node(static_cast<xml_document_struct*>(page->allocator));3704 }3705 3706 const char_t* xml_node::child_value() const3707 {3708 if (!_root) return PUGIXML_TEXT("");3709 3710 6070 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) 3711 { 3712 xml_node_type type = static_cast<xml_node_type>((i->header & xml_memory_page_type_mask) + 1); 3713 3714 if (i->value && (type == node_pcdata || type == node_cdata)) 3715 return i->value; 3716 } 3717 3718 return PUGIXML_TEXT(""); 3719 } 3720 3721 const char_t* xml_node::child_value(const char_t* name) const 3722 { 3723 return child(name).child_value(); 3724 } 3725 3726 xml_attribute xml_node::first_attribute() const 3727 { 3728 return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); 3729 } 3730 3731 xml_attribute xml_node::last_attribute() const 3732 { 3733 return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); 3734 } 3735 3736 xml_node xml_node::first_child() const 3737 { 3738 return _root ? xml_node(_root->first_child) : xml_node(); 3739 } 3740 3741 xml_node xml_node::last_child() const 3742 { 3743 return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); 3744 } 3745 3746 bool xml_node::set_name(const char_t* rhs) 3747 { 3748 switch (type()) 3749 { 3750 case node_pi: 3751 case node_declaration: 3752 case node_element: 3753 return strcpy_insitu(_root->name, _root->header, xml_memory_page_name_allocated_mask, rhs); 3754 3755 default: 3756 return false; 3757 } 3758 } 3759 3760 bool xml_node::set_value(const char_t* rhs) 3761 { 3762 switch (type()) 3763 { 3764 case node_pi: 3765 case node_cdata: 3766 case node_pcdata: 3767 case node_comment: 3768 case node_doctype: 3769 return strcpy_insitu(_root->value, _root->header, xml_memory_page_value_allocated_mask, rhs); 3770 3771 default: 3772 return false; 3773 } 3774 } 3775 3776 xml_attribute xml_node::append_attribute(const char_t* name) 3777 { 3778 if (type() != node_element && type() != node_declaration) return xml_attribute(); 3779 3780 xml_attribute a(append_attribute_ll(_root, get_allocator(_root))); 3781 a.set_name(name); 3782 3783 return a; 3784 } 3785 3786 xml_attribute xml_node::prepend_attribute(const char_t* name) 3787 { 3788 if (type() != node_element && type() != node_declaration) return xml_attribute(); 3789 3790 xml_attribute a(allocate_attribute(get_allocator(_root))); 3791 if (!a) return xml_attribute(); 3792 3793 a.set_name(name); 3794 3795 xml_attribute_struct* head = _root->first_attribute; 3796 3797 if (head) 3798 { 3799 a._attr->prev_attribute_c = head->prev_attribute_c; 3800 head->prev_attribute_c = a._attr; 3801 } 3802 else 3803 a._attr->prev_attribute_c = a._attr; 3804 3805 a._attr->next_attribute = head; 3806 _root->first_attribute = a._attr; 3807 3808 return a; 3809 } 3810 3811 xml_attribute xml_node::insert_attribute_before(const char_t* name, const xml_attribute& attr) 3812 { 3813 if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); 3814 3815 // check that attribute belongs to *this 3816 xml_attribute_struct* cur = attr._attr; 3817 3818 while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; 3819 3820 if (cur != _root->first_attribute) return xml_attribute(); 3821 3822 xml_attribute a(allocate_attribute(get_allocator(_root))); 3823 if (!a) return xml_attribute(); 3824 3825 a.set_name(name); 3826 3827 if (attr._attr->prev_attribute_c->next_attribute) 3828 attr._attr->prev_attribute_c->next_attribute = a._attr; 3829 else 3830 _root->first_attribute = a._attr; 3831 3832 a._attr->prev_attribute_c = attr._attr->prev_attribute_c; 3833 a._attr->next_attribute = attr._attr; 3834 attr._attr->prev_attribute_c = a._attr; 3835 3836 return a; 3837 } 3838 3839 xml_attribute xml_node::insert_attribute_after(const char_t* name, const xml_attribute& attr) 3840 { 3841 if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute(); 3842 3843 // check that attribute belongs to *this 3844 xml_attribute_struct* cur = attr._attr; 3845 3846 while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c; 3847 3848 if (cur != _root->first_attribute) return xml_attribute(); 3849 3850 xml_attribute a(allocate_attribute(get_allocator(_root))); 3851 if (!a) return xml_attribute(); 3852 3853 a.set_name(name); 3854 3855 if (attr._attr->next_attribute) 3856 attr._attr->next_attribute->prev_attribute_c = a._attr; 3857 else 3858 _root->first_attribute->prev_attribute_c = a._attr; 3859 3860 a._attr->next_attribute = attr._attr->next_attribute; 3861 a._attr->prev_attribute_c = attr._attr; 3862 attr._attr->next_attribute = a._attr; 3863 3864 return a; 3865 } 3866 3867 xml_attribute xml_node::append_copy(const xml_attribute& proto) 3868 { 3869 if (!proto) return xml_attribute(); 3870 3871 xml_attribute result = append_attribute(proto.name()); 3872 result.set_value(proto.value()); 3873 3874 return result; 3875 } 3876 3877 xml_attribute xml_node::prepend_copy(const xml_attribute& proto) 3878 { 3879 if (!proto) return xml_attribute(); 3880 3881 xml_attribute result = prepend_attribute(proto.name()); 3882 result.set_value(proto.value()); 3883 3884 return result; 3885 } 3886 3887 xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr) 3888 { 3889 if (!proto) return xml_attribute(); 3890 3891 xml_attribute result = insert_attribute_after(proto.name(), attr); 3892 result.set_value(proto.value()); 3893 3894 return result; 3895 } 3896 3897 xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr) 3898 { 3899 if (!proto) return xml_attribute(); 3900 3901 xml_attribute result = insert_attribute_before(proto.name(), attr); 3902 result.set_value(proto.value()); 3903 3904 return result; 3905 } 3906 3907 xml_node xml_node::append_child(xml_node_type type) 3908 { 3909 if (!allow_insert_child(this->type(), type)) return xml_node(); 3910 3911 xml_node n(append_node(_root, get_allocator(_root), type)); 3912 3913 if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); 3914 3915 return n; 3916 } 3917 3918 xml_node xml_node::prepend_child(xml_node_type type) 3919 { 3920 if (!allow_insert_child(this->type(), type)) return xml_node(); 3921 3922 xml_node n(allocate_node(get_allocator(_root), type)); 3923 if (!n) return xml_node(); 3924 3925 n._root->parent = _root; 3926 3927 xml_node_struct* head = _root->first_child; 3928 3929 if (head) 3930 { 3931 n._root->prev_sibling_c = head->prev_sibling_c; 3932 head->prev_sibling_c = n._root; 3933 } 3934 else 3935 n._root->prev_sibling_c = n._root; 3936 3937 n._root->next_sibling = head; 3938 _root->first_child = n._root; 3939 3940 if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); 3941 3942 return n; 3943 } 3944 3945 xml_node xml_node::insert_child_before(xml_node_type type, const xml_node& node) 3946 { 3947 if (!allow_insert_child(this->type(), type)) return xml_node(); 3948 if (!node._root || node._root->parent != _root) return xml_node(); 3949 3950 xml_node n(allocate_node(get_allocator(_root), type)); 3951 if (!n) return xml_node(); 3952 3953 n._root->parent = _root; 3954 3955 if (node._root->prev_sibling_c->next_sibling) 3956 node._root->prev_sibling_c->next_sibling = n._root; 3957 else 3958 _root->first_child = n._root; 3959 3960 n._root->prev_sibling_c = node._root->prev_sibling_c; 3961 n._root->next_sibling = node._root; 3962 node._root->prev_sibling_c = n._root; 3963 3964 if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); 3965 3966 return n; 3967 } 3968 3969 xml_node xml_node::insert_child_after(xml_node_type type, const xml_node& node) 3970 { 3971 if (!allow_insert_child(this->type(), type)) return xml_node(); 3972 if (!node._root || node._root->parent != _root) return xml_node(); 3973 3974 xml_node n(allocate_node(get_allocator(_root), type)); 3975 if (!n) return xml_node(); 3976 3977 n._root->parent = _root; 3978 3979 if (node._root->next_sibling) 3980 node._root->next_sibling->prev_sibling_c = n._root; 3981 else 3982 _root->first_child->prev_sibling_c = n._root; 3983 3984 n._root->next_sibling = node._root->next_sibling; 3985 n._root->prev_sibling_c = node._root; 3986 node._root->next_sibling = n._root; 3987 3988 if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); 3989 3990 return n; 3991 } 3992 3993 xml_node xml_node::append_child(const char_t* name) 3994 { 3995 xml_node result = append_child(node_element); 3996 3997 result.set_name(name); 3998 3999 return result; 4000 } 4001 4002 xml_node xml_node::prepend_child(const char_t* name) 4003 { 4004 xml_node result = prepend_child(node_element); 4005 4006 result.set_name(name); 4007 4008 return result; 4009 } 4010 4011 xml_node xml_node::insert_child_after(const char_t* name, const xml_node& node) 4012 { 4013 xml_node result = insert_child_after(node_element, node); 4014 4015 result.set_name(name); 4016 4017 return result; 4018 } 4019 4020 xml_node xml_node::insert_child_before(const char_t* name, const xml_node& node) 4021 { 4022 xml_node result = insert_child_before(node_element, node); 4023 4024 result.set_name(name); 4025 4026 return result; 4027 } 4028 4029 xml_node xml_node::append_copy(const xml_node& proto) 4030 { 4031 xml_node result = append_child(proto.type()); 4032 4033 if (result) recursive_copy_skip(result, proto, result); 4034 4035 return result; 4036 } 4037 4038 xml_node xml_node::prepend_copy(const xml_node& proto) 4039 { 4040 xml_node result = prepend_child(proto.type()); 4041 4042 if (result) recursive_copy_skip(result, proto, result); 4043 4044 return result; 4045 } 4046 4047 xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) 4048 { 4049 xml_node result = insert_child_after(proto.type(), node); 4050 4051 if (result) recursive_copy_skip(result, proto, result); 4052 4053 return result; 4054 } 4055 4056 xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) 4057 { 4058 xml_node result = insert_child_before(proto.type(), node); 4059 4060 if (result) recursive_copy_skip(result, proto, result); 4061 4062 return result; 4063 } 4064 4065 bool xml_node::remove_attribute(const char_t* name) 4066 { 4067 return remove_attribute(attribute(name)); 4068 } 4069 4070 bool xml_node::remove_attribute(const xml_attribute& a) 4071 { 4072 if (!_root || !a._attr) return false; 4073 4074 // check that attribute belongs to *this 4075 xml_attribute_struct* attr = a._attr; 4076 4077 while (attr->prev_attribute_c->next_attribute) attr = attr->prev_attribute_c; 4078 4079 if (attr != _root->first_attribute) return false; 4080 4081 if (a._attr->next_attribute) a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c; 4082 else if (_root->first_attribute) _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c; 4083 4084 if (a._attr->prev_attribute_c->next_attribute) a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute; 4085 else _root->first_attribute = a._attr->next_attribute; 4086 4087 destroy_attribute(a._attr, get_allocator(_root)); 4088 4089 return true; 4090 } 4091 4092 bool xml_node::remove_child(const char_t* name) 4093 { 4094 return remove_child(child(name)); 4095 } 4096 4097 bool xml_node::remove_child(const xml_node& n) 4098 { 4099 if (!_root || !n._root || n._root->parent != _root) return false; 4100 4101 if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c; 4102 else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c; 4103 4104 if (n._root->prev_sibling_c->next_sibling) n._root->prev_sibling_c->next_sibling = n._root->next_sibling; 4105 else _root->first_child = n._root->next_sibling; 4106 4107 destroy_node(n._root, get_allocator(_root)); 4108 4109 return true; 4110 } 4111 4112 xml_node xml_node::find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const 6071 if (i->name && impl::strequal(name_, i->name)) 6072 { 6073 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) 6074 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) 6075 return xml_node(i); 6076 } 6077 6078 return xml_node(); 6079 } 6080 6081 PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const 4113 6082 { 4114 6083 if (!_root) return xml_node(); 4115 4116 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) 4117 if (i->name && strequal(name, i->name)) 4118 { 4119 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) 4120 if (strequal(attr_name, a->name) && strequal(attr_value, a->value)) 4121 return xml_node(i); 4122 } 4123 4124 return xml_node(); 4125 } 4126 4127 xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const 4128 { 4129 if (!_root) return xml_node(); 4130 6084 4131 6085 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) 4132 6086 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) 4133 if ( strequal(attr_name, a->name) && strequal(attr_value, a->value))6087 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) 4134 6088 return xml_node(i); 4135 6089 … … 4138 6092 4139 6093 #ifndef PUGIXML_NO_STL 4140 string_t xml_node::path(char_t delimiter) const 4141 { 4142 string_t path; 4143 4144 xml_node cursor = *this; // Make a copy. 4145 4146 path = cursor.name(); 4147 4148 while (cursor.parent()) 4149 { 4150 cursor = cursor.parent(); 4151 4152 string_t temp = cursor.name(); 4153 temp += delimiter; 4154 temp += path; 4155 path.swap(temp); 4156 } 4157 4158 return path; 6094 PUGI__FN string_t xml_node::path(char_t delimiter) const 6095 { 6096 if (!_root) return string_t(); 6097 6098 size_t offset = 0; 6099 6100 for (xml_node_struct* i = _root; i; i = i->parent) 6101 { 6102 offset += (i != _root); 6103 offset += i->name ? impl::strlength(i->name) : 0; 6104 } 6105 6106 string_t result; 6107 result.resize(offset); 6108 6109 for (xml_node_struct* j = _root; j; j = j->parent) 6110 { 6111 if (j != _root) 6112 result[--offset] = delimiter; 6113 6114 if (j->name && *j->name) 6115 { 6116 size_t length = impl::strlength(j->name); 6117 6118 offset -= length; 6119 memcpy(&result[offset], j->name, length * sizeof(char_t)); 6120 } 6121 } 6122 6123 assert(offset == 0); 6124 6125 return result; 4159 6126 } 4160 6127 #endif 4161 6128 4162 xml_node xml_node::first_element_by_path(const char_t* path, char_t delimiter) const6129 PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const 4163 6130 { 4164 6131 xml_node found = *this; // Current search context. 4165 6132 4166 if (!_root || !path || !path[0]) return found;4167 4168 if (path [0] == delimiter)6133 if (!_root || !path_ || !path_[0]) return found; 6134 6135 if (path_[0] == delimiter) 4169 6136 { 4170 6137 // Absolute path; e.g. '/foo/bar' 4171 6138 found = found.root(); 4172 ++path ;4173 } 4174 4175 const char_t* path_segment = path ;6139 ++path_; 6140 } 6141 6142 const char_t* path_segment = path_; 4176 6143 4177 6144 while (*path_segment == delimiter) ++path_segment; … … 4195 6162 for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling) 4196 6163 { 4197 if (j->name && strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))6164 if (j->name && impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment))) 4198 6165 { 4199 6166 xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); … … 4207 6174 } 4208 6175 4209 bool xml_node::traverse(xml_tree_walker& walker)6176 PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) 4210 6177 { 4211 6178 walker._depth = -1; 4212 6179 4213 6180 xml_node arg_begin = *this; 4214 6181 if (!walker.begin(arg_begin)) return false; 4215 6182 4216 6183 xml_node cur = first_child(); 4217 6184 4218 6185 if (cur) 4219 6186 { 4220 6187 ++walker._depth; 4221 6188 4222 do 6189 do 4223 6190 { 4224 6191 xml_node arg_for_each = cur; 4225 6192 if (!walker.for_each(arg_for_each)) 4226 6193 return false; 4227 6194 4228 6195 if (cur.first_child()) 4229 6196 { … … 4236 6203 { 4237 6204 // Borland C++ workaround 4238 while (!cur.next_sibling() && cur != *this && (bool)cur.parent())6205 while (!cur.next_sibling() && cur != *this && !cur.parent().empty()) 4239 6206 { 4240 6207 --walker._depth; 4241 6208 cur = cur.parent(); 4242 6209 } 4243 6210 4244 6211 if (cur != *this) 4245 6212 cur = cur.next_sibling(); … … 4255 6222 } 4256 6223 4257 4258 4259 4260 4261 4262 xml_node_struct* xml_node::internal_object() const4263 { 4264 4265 } 4266 4267 void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const6224 PUGI__FN size_t xml_node::hash_value() const 6225 { 6226 return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct)); 6227 } 6228 6229 PUGI__FN xml_node_struct* xml_node::internal_object() const 6230 { 6231 return _root; 6232 } 6233 6234 PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const 4268 6235 { 4269 6236 if (!_root) return; 4270 6237 4271 xml_buffered_writer buffered_writer(writer, encoding); 4272 4273 node_output(buffered_writer, *this, indent, flags, depth); 6238 impl::xml_buffered_writer buffered_writer(writer, encoding); 6239 6240 impl::node_output(buffered_writer, _root, indent, flags, depth); 6241 6242 buffered_writer.flush(); 4274 6243 } 4275 6244 4276 6245 #ifndef PUGIXML_NO_STL 4277 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) const6246 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 4278 6247 { 4279 6248 xml_writer_stream writer(stream); … … 4282 6251 } 4283 6252 4284 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) const6253 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 4285 6254 { 4286 6255 xml_writer_stream writer(stream); … … 4290 6259 #endif 4291 6260 4292 ptrdiff_t xml_node::offset_debug() const 4293 { 4294 xml_node_struct* r = root()._root; 4295 4296 if (!r) return -1; 4297 4298 const char_t* buffer = static_cast<xml_document_struct*>(r)->buffer; 4299 4300 if (!buffer) return -1; 6261 PUGI__FN ptrdiff_t xml_node::offset_debug() const 6262 { 6263 if (!_root) return -1; 6264 6265 impl::xml_document_struct& doc = impl::get_document(_root); 6266 6267 // we can determine the offset reliably only if there is exactly once parse buffer 6268 if (!doc.buffer || doc.extra_buffers) return -1; 4301 6269 4302 6270 switch (type()) … … 4308 6276 case node_declaration: 4309 6277 case node_pi: 4310 return (_root->header & xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer;6278 return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1; 4311 6279 4312 6280 case node_pcdata: … … 4314 6282 case node_comment: 4315 6283 case node_doctype: 4316 return (_root->header & xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer;6284 return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1; 4317 6285 4318 6286 default: … … 4322 6290 4323 6291 #ifdef __BORLANDC__ 4324 bool operator&&(const xml_node& lhs, bool rhs)6292 PUGI__FN bool operator&&(const xml_node& lhs, bool rhs) 4325 6293 { 4326 6294 return (bool)lhs && rhs; 4327 6295 } 4328 6296 4329 bool operator||(const xml_node& lhs, bool rhs)6297 PUGI__FN bool operator||(const xml_node& lhs, bool rhs) 4330 6298 { 4331 6299 return (bool)lhs || rhs; … … 4333 6301 #endif 4334 6302 4335 xml_node_iterator::xml_node_iterator() 4336 { 4337 } 4338 4339 xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) 4340 { 4341 } 4342 4343 xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) 4344 { 4345 } 4346 4347 bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const 6303 PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root) 6304 { 6305 } 6306 6307 PUGI__FN xml_node_struct* xml_text::_data() const 6308 { 6309 if (!_root || impl::is_text_node(_root)) return _root; 6310 6311 // element nodes can have value if parse_embed_pcdata was used 6312 if (PUGI__NODETYPE(_root) == node_element && _root->value) 6313 return _root; 6314 6315 for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) 6316 if (impl::is_text_node(node)) 6317 return node; 6318 6319 return 0; 6320 } 6321 6322 PUGI__FN xml_node_struct* xml_text::_data_new() 6323 { 6324 xml_node_struct* d = _data(); 6325 if (d) return d; 6326 6327 return xml_node(_root).append_child(node_pcdata).internal_object(); 6328 } 6329 6330 PUGI__FN xml_text::xml_text(): _root(0) 6331 { 6332 } 6333 6334 PUGI__FN static void unspecified_bool_xml_text(xml_text***) 6335 { 6336 } 6337 6338 PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const 6339 { 6340 return _data() ? unspecified_bool_xml_text : 0; 6341 } 6342 6343 PUGI__FN bool xml_text::operator!() const 6344 { 6345 return !_data(); 6346 } 6347 6348 PUGI__FN bool xml_text::empty() const 6349 { 6350 return _data() == 0; 6351 } 6352 6353 PUGI__FN const char_t* xml_text::get() const 6354 { 6355 xml_node_struct* d = _data(); 6356 6357 return (d && d->value) ? d->value + 0 : PUGIXML_TEXT(""); 6358 } 6359 6360 PUGI__FN const char_t* xml_text::as_string(const char_t* def) const 6361 { 6362 xml_node_struct* d = _data(); 6363 6364 return (d && d->value) ? d->value + 0 : def; 6365 } 6366 6367 PUGI__FN int xml_text::as_int(int def) const 6368 { 6369 xml_node_struct* d = _data(); 6370 6371 return (d && d->value) ? impl::get_value_int(d->value) : def; 6372 } 6373 6374 PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const 6375 { 6376 xml_node_struct* d = _data(); 6377 6378 return (d && d->value) ? impl::get_value_uint(d->value) : def; 6379 } 6380 6381 PUGI__FN double xml_text::as_double(double def) const 6382 { 6383 xml_node_struct* d = _data(); 6384 6385 return (d && d->value) ? impl::get_value_double(d->value) : def; 6386 } 6387 6388 PUGI__FN float xml_text::as_float(float def) const 6389 { 6390 xml_node_struct* d = _data(); 6391 6392 return (d && d->value) ? impl::get_value_float(d->value) : def; 6393 } 6394 6395 PUGI__FN bool xml_text::as_bool(bool def) const 6396 { 6397 xml_node_struct* d = _data(); 6398 6399 return (d && d->value) ? impl::get_value_bool(d->value) : def; 6400 } 6401 6402 #ifdef PUGIXML_HAS_LONG_LONG 6403 PUGI__FN long long xml_text::as_llong(long long def) const 6404 { 6405 xml_node_struct* d = _data(); 6406 6407 return (d && d->value) ? impl::get_value_llong(d->value) : def; 6408 } 6409 6410 PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const 6411 { 6412 xml_node_struct* d = _data(); 6413 6414 return (d && d->value) ? impl::get_value_ullong(d->value) : def; 6415 } 6416 #endif 6417 6418 PUGI__FN bool xml_text::set(const char_t* rhs) 6419 { 6420 xml_node_struct* dn = _data_new(); 6421 6422 return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false; 6423 } 6424 6425 PUGI__FN bool xml_text::set(int rhs) 6426 { 6427 xml_node_struct* dn = _data_new(); 6428 6429 return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; 6430 } 6431 6432 PUGI__FN bool xml_text::set(unsigned int rhs) 6433 { 6434 xml_node_struct* dn = _data_new(); 6435 6436 return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; 6437 } 6438 6439 PUGI__FN bool xml_text::set(long rhs) 6440 { 6441 xml_node_struct* dn = _data_new(); 6442 6443 return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; 6444 } 6445 6446 PUGI__FN bool xml_text::set(unsigned long rhs) 6447 { 6448 xml_node_struct* dn = _data_new(); 6449 6450 return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; 6451 } 6452 6453 PUGI__FN bool xml_text::set(float rhs) 6454 { 6455 xml_node_struct* dn = _data_new(); 6456 6457 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; 6458 } 6459 6460 PUGI__FN bool xml_text::set(double rhs) 6461 { 6462 xml_node_struct* dn = _data_new(); 6463 6464 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; 6465 } 6466 6467 PUGI__FN bool xml_text::set(bool rhs) 6468 { 6469 xml_node_struct* dn = _data_new(); 6470 6471 return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; 6472 } 6473 6474 #ifdef PUGIXML_HAS_LONG_LONG 6475 PUGI__FN bool xml_text::set(long long rhs) 6476 { 6477 xml_node_struct* dn = _data_new(); 6478 6479 return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; 6480 } 6481 6482 PUGI__FN bool xml_text::set(unsigned long long rhs) 6483 { 6484 xml_node_struct* dn = _data_new(); 6485 6486 return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; 6487 } 6488 #endif 6489 6490 PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) 6491 { 6492 set(rhs); 6493 return *this; 6494 } 6495 6496 PUGI__FN xml_text& xml_text::operator=(int rhs) 6497 { 6498 set(rhs); 6499 return *this; 6500 } 6501 6502 PUGI__FN xml_text& xml_text::operator=(unsigned int rhs) 6503 { 6504 set(rhs); 6505 return *this; 6506 } 6507 6508 PUGI__FN xml_text& xml_text::operator=(long rhs) 6509 { 6510 set(rhs); 6511 return *this; 6512 } 6513 6514 PUGI__FN xml_text& xml_text::operator=(unsigned long rhs) 6515 { 6516 set(rhs); 6517 return *this; 6518 } 6519 6520 PUGI__FN xml_text& xml_text::operator=(double rhs) 6521 { 6522 set(rhs); 6523 return *this; 6524 } 6525 6526 PUGI__FN xml_text& xml_text::operator=(float rhs) 6527 { 6528 set(rhs); 6529 return *this; 6530 } 6531 6532 PUGI__FN xml_text& xml_text::operator=(bool rhs) 6533 { 6534 set(rhs); 6535 return *this; 6536 } 6537 6538 #ifdef PUGIXML_HAS_LONG_LONG 6539 PUGI__FN xml_text& xml_text::operator=(long long rhs) 6540 { 6541 set(rhs); 6542 return *this; 6543 } 6544 6545 PUGI__FN xml_text& xml_text::operator=(unsigned long long rhs) 6546 { 6547 set(rhs); 6548 return *this; 6549 } 6550 #endif 6551 6552 PUGI__FN xml_node xml_text::data() const 6553 { 6554 return xml_node(_data()); 6555 } 6556 6557 #ifdef __BORLANDC__ 6558 PUGI__FN bool operator&&(const xml_text& lhs, bool rhs) 6559 { 6560 return (bool)lhs && rhs; 6561 } 6562 6563 PUGI__FN bool operator||(const xml_text& lhs, bool rhs) 6564 { 6565 return (bool)lhs || rhs; 6566 } 6567 #endif 6568 6569 PUGI__FN xml_node_iterator::xml_node_iterator() 6570 { 6571 } 6572 6573 PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent()) 6574 { 6575 } 6576 6577 PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) 6578 { 6579 } 6580 6581 PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const 4348 6582 { 4349 6583 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; 4350 6584 } 4351 4352 bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const6585 6586 PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const 4353 6587 { 4354 6588 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; 4355 6589 } 4356 6590 4357 xml_node& xml_node_iterator::operator*()6591 PUGI__FN xml_node& xml_node_iterator::operator*() const 4358 6592 { 4359 6593 assert(_wrap._root); … … 4361 6595 } 4362 6596 4363 xml_node* xml_node_iterator::operator->()6597 PUGI__FN xml_node* xml_node_iterator::operator->() const 4364 6598 { 4365 6599 assert(_wrap._root); 4366 return &_wrap;4367 } 4368 4369 const xml_node_iterator& xml_node_iterator::operator++()6600 return const_cast<xml_node*>(&_wrap); // BCC5 workaround 6601 } 6602 6603 PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() 4370 6604 { 4371 6605 assert(_wrap._root); … … 4374 6608 } 4375 6609 4376 xml_node_iterator xml_node_iterator::operator++(int)6610 PUGI__FN xml_node_iterator xml_node_iterator::operator++(int) 4377 6611 { 4378 6612 xml_node_iterator temp = *this; … … 4381 6615 } 4382 6616 4383 const xml_node_iterator& xml_node_iterator::operator--()6617 PUGI__FN const xml_node_iterator& xml_node_iterator::operator--() 4384 6618 { 4385 6619 _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child(); … … 4387 6621 } 4388 6622 4389 xml_node_iterator xml_node_iterator::operator--(int)6623 PUGI__FN xml_node_iterator xml_node_iterator::operator--(int) 4390 6624 { 4391 6625 xml_node_iterator temp = *this; … … 4394 6628 } 4395 6629 4396 xml_attribute_iterator::xml_attribute_iterator()4397 { 4398 } 4399 4400 xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)4401 { 4402 } 4403 4404 xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)4405 { 4406 } 4407 4408 bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const6630 PUGI__FN xml_attribute_iterator::xml_attribute_iterator() 6631 { 6632 } 6633 6634 PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent) 6635 { 6636 } 6637 6638 PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent) 6639 { 6640 } 6641 6642 PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const 4409 6643 { 4410 6644 return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; 4411 6645 } 4412 4413 bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const6646 6647 PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const 4414 6648 { 4415 6649 return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; 4416 6650 } 4417 6651 4418 xml_attribute& xml_attribute_iterator::operator*()6652 PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const 4419 6653 { 4420 6654 assert(_wrap._attr); … … 4422 6656 } 4423 6657 4424 xml_attribute* xml_attribute_iterator::operator->()6658 PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const 4425 6659 { 4426 6660 assert(_wrap._attr); 4427 return &_wrap;4428 } 4429 4430 const xml_attribute_iterator& xml_attribute_iterator::operator++()6661 return const_cast<xml_attribute*>(&_wrap); // BCC5 workaround 6662 } 6663 6664 PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() 4431 6665 { 4432 6666 assert(_wrap._attr); … … 4435 6669 } 4436 6670 4437 xml_attribute_iterator xml_attribute_iterator::operator++(int)6671 PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int) 4438 6672 { 4439 6673 xml_attribute_iterator temp = *this; … … 4442 6676 } 4443 6677 4444 const xml_attribute_iterator& xml_attribute_iterator::operator--()6678 PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--() 4445 6679 { 4446 6680 _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute(); … … 4448 6682 } 4449 6683 4450 xml_attribute_iterator xml_attribute_iterator::operator--(int)6684 PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int) 4451 6685 { 4452 6686 xml_attribute_iterator temp = *this; … … 4455 6689 } 4456 6690 4457 xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) 4458 { 4459 } 4460 4461 xml_parse_result::operator bool() const 4462 { 4463 return status == status_ok; 4464 } 4465 4466 const char* xml_parse_result::description() const 6691 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0) 6692 { 6693 } 6694 6695 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name) 6696 { 6697 } 6698 6699 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name) 6700 { 6701 } 6702 6703 PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const 6704 { 6705 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; 6706 } 6707 6708 PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const 6709 { 6710 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; 6711 } 6712 6713 PUGI__FN xml_node& xml_named_node_iterator::operator*() const 6714 { 6715 assert(_wrap._root); 6716 return _wrap; 6717 } 6718 6719 PUGI__FN xml_node* xml_named_node_iterator::operator->() const 6720 { 6721 assert(_wrap._root); 6722 return const_cast<xml_node*>(&_wrap); // BCC5 workaround 6723 } 6724 6725 PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() 6726 { 6727 assert(_wrap._root); 6728 _wrap = _wrap.next_sibling(_name); 6729 return *this; 6730 } 6731 6732 PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int) 6733 { 6734 xml_named_node_iterator temp = *this; 6735 ++*this; 6736 return temp; 6737 } 6738 6739 PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator--() 6740 { 6741 if (_wrap._root) 6742 _wrap = _wrap.previous_sibling(_name); 6743 else 6744 { 6745 _wrap = _parent.last_child(); 6746 6747 if (!impl::strequal(_wrap.name(), _name)) 6748 _wrap = _wrap.previous_sibling(_name); 6749 } 6750 6751 return *this; 6752 } 6753 6754 PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator--(int) 6755 { 6756 xml_named_node_iterator temp = *this; 6757 --*this; 6758 return temp; 6759 } 6760 6761 PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto) 6762 { 6763 } 6764 6765 PUGI__FN xml_parse_result::operator bool() const 6766 { 6767 return status == status_ok; 6768 } 6769 6770 PUGI__FN const char* xml_parse_result::description() const 4467 6771 { 4468 6772 switch (status) … … 4487 6791 case status_end_element_mismatch: return "Start-end tags mismatch"; 4488 6792 6793 case status_append_invalid_root: return "Unable to append nodes: root is not an element or document"; 6794 6795 case status_no_document_element: return "No document element found"; 6796 4489 6797 default: return "Unknown error"; 4490 6798 } 4491 6799 } 4492 6800 4493 xml_document::xml_document(): _buffer(0) 4494 { 4495 create(); 4496 } 4497 4498 xml_document::~xml_document() 4499 { 4500 destroy(); 4501 } 4502 4503 void xml_document::reset() 4504 { 4505 destroy(); 4506 create(); 4507 } 4508 4509 void xml_document::reset(const xml_document& proto) 4510 { 4511 reset(); 4512 4513 for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) 4514 append_copy(cur); 4515 } 4516 4517 void xml_document::create() 4518 { 6801 PUGI__FN xml_document::xml_document(): _buffer(0) 6802 { 6803 _create(); 6804 } 6805 6806 PUGI__FN xml_document::~xml_document() 6807 { 6808 _destroy(); 6809 } 6810 6811 PUGI__FN void xml_document::reset() 6812 { 6813 _destroy(); 6814 _create(); 6815 } 6816 6817 PUGI__FN void xml_document::reset(const xml_document& proto) 6818 { 6819 reset(); 6820 6821 for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) 6822 append_copy(cur); 6823 } 6824 6825 PUGI__FN void xml_document::_create() 6826 { 6827 assert(!_root); 6828 6829 #ifdef PUGIXML_COMPACT 6830 const size_t page_offset = sizeof(uint32_t); 6831 #else 6832 const size_t page_offset = 0; 6833 #endif 6834 4519 6835 // initialize sentinel page 4520 STATIC_ASSERT(offsetof(xml_memory_page, data) + sizeof(xml_document_struct) + xml_memory_page_alignment <= sizeof(_memory)); 4521 4522 // align upwards to page boundary 4523 void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(_memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1)); 6836 PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory)); 4524 6837 4525 6838 // prepare page structure 4526 xml_memory_page* page = xml_memory_page::construct(page_memory); 4527 4528 page->busy_size = xml_memory_page_size; 6839 impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory); 6840 assert(page); 6841 6842 page->busy_size = impl::xml_memory_page_size; 6843 6844 // setup first page marker 6845 #ifdef PUGIXML_COMPACT 6846 // round-trip through void* to avoid 'cast increases required alignment of target type' warning 6847 page->compact_page_marker = reinterpret_cast<uint32_t*>(static_cast<void*>(reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page))); 6848 *page->compact_page_marker = sizeof(impl::xml_memory_page); 6849 #endif 4529 6850 4530 6851 // allocate new root 4531 _root = new ( page->data)xml_document_struct(page);6852 _root = new (reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page); 4532 6853 _root->prev_sibling_c = _root; 4533 6854 4534 6855 // setup sentinel page 4535 page->allocator = static_cast<xml_document_struct*>(_root); 4536 } 4537 4538 void xml_document::destroy() 4539 { 6856 page->allocator = static_cast<impl::xml_document_struct*>(_root); 6857 6858 // setup hash table pointer in allocator 6859 #ifdef PUGIXML_COMPACT 6860 page->allocator->_hash = &static_cast<impl::xml_document_struct*>(_root)->hash; 6861 #endif 6862 6863 // verify the document allocation 6864 assert(reinterpret_cast<char*>(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory)); 6865 } 6866 6867 PUGI__FN void xml_document::_destroy() 6868 { 6869 assert(_root); 6870 4540 6871 // destroy static storage 4541 6872 if (_buffer) 4542 6873 { 4543 global_deallocate(_buffer);6874 impl::xml_memory::deallocate(_buffer); 4544 6875 _buffer = 0; 4545 6876 } 4546 6877 6878 // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator) 6879 for (impl::xml_extra_buffer* extra = static_cast<impl::xml_document_struct*>(_root)->extra_buffers; extra; extra = extra->next) 6880 { 6881 if (extra->buffer) impl::xml_memory::deallocate(extra->buffer); 6882 } 6883 4547 6884 // destroy dynamic storage, leave sentinel page (it's in static memory) 4548 if (_root) 4549 { 4550 xml_memory_page* root_page = reinterpret_cast<xml_memory_page*>(_root->header & xml_memory_page_pointer_mask); 4551 assert(root_page && !root_page->prev && !root_page->memory); 4552 4553 // destroy all pages 4554 for (xml_memory_page* page = root_page->next; page; ) 4555 { 4556 xml_memory_page* next = page->next; 4557 4558 xml_allocator::deallocate_page(page); 4559 4560 page = next; 4561 } 4562 4563 // cleanup root page 4564 root_page->allocator = 0; 4565 root_page->next = 0; 4566 root_page->busy_size = root_page->freed_size = 0; 4567 4568 _root = 0; 4569 } 6885 impl::xml_memory_page* root_page = PUGI__GETPAGE(_root); 6886 assert(root_page && !root_page->prev); 6887 assert(reinterpret_cast<char*>(root_page) >= _memory && reinterpret_cast<char*>(root_page) < _memory + sizeof(_memory)); 6888 6889 for (impl::xml_memory_page* page = root_page->next; page; ) 6890 { 6891 impl::xml_memory_page* next = page->next; 6892 6893 impl::xml_allocator::deallocate_page(page); 6894 6895 page = next; 6896 } 6897 6898 #ifdef PUGIXML_COMPACT 6899 // destroy hash table 6900 static_cast<impl::xml_document_struct*>(_root)->hash.clear(); 6901 #endif 6902 6903 _root = 0; 4570 6904 } 4571 6905 4572 6906 #ifndef PUGIXML_NO_STL 4573 xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding)6907 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding) 4574 6908 { 4575 6909 reset(); 4576 6910 4577 return load_stream_impl(*this, stream, options, encoding);4578 } 4579 4580 xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)6911 return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding, &_buffer); 6912 } 6913 6914 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options) 4581 6915 { 4582 6916 reset(); 4583 6917 4584 return load_stream_impl(*this, stream, options, encoding_wchar);6918 return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding_wchar, &_buffer); 4585 6919 } 4586 6920 #endif 4587 6921 4588 xml_parse_result xml_document::load(const char_t* contents, unsigned int options)6922 PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options) 4589 6923 { 4590 6924 // Force native encoding (skip autodetection) … … 4595 6929 #endif 4596 6930 4597 return load_buffer(contents, strlength(contents) * sizeof(char_t), options, encoding); 4598 } 4599 4600 xml_parse_result xml_document::load_file(const char* path, unsigned int options, xml_encoding encoding) 6931 return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding); 6932 } 6933 6934 PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) 6935 { 6936 return load_string(contents, options); 6937 } 6938 6939 PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) 4601 6940 { 4602 6941 reset(); 4603 6942 4604 FILE* file = fopen(path, "rb"); 4605 4606 return load_file_impl(*this, file, options, encoding); 4607 } 4608 4609 xml_parse_result xml_document::load_file(const wchar_t* path, unsigned int options, xml_encoding encoding) 6943 using impl::auto_deleter; // MSVC7 workaround 6944 auto_deleter<FILE> file(fopen(path_, "rb"), impl::close_file); 6945 6946 return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer); 6947 } 6948 6949 PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) 4610 6950 { 4611 6951 reset(); 4612 6952 4613 FILE* file = open_file_wide(path, L"rb"); 4614 4615 return load_file_impl(*this, file, options, encoding); 4616 } 4617 4618 xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own) 6953 using impl::auto_deleter; // MSVC7 workaround 6954 auto_deleter<FILE> file(impl::open_file_wide(path_, L"rb"), impl::close_file); 6955 6956 return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer); 6957 } 6958 6959 PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) 4619 6960 { 4620 6961 reset(); 4621 6962 4622 // check input buffer 4623 assert(contents || size == 0); 4624 4625 // get actual encoding 4626 xml_encoding buffer_encoding = get_buffer_encoding(encoding, contents, size); 4627 4628 // get private buffer 4629 char_t* buffer = 0; 4630 size_t length = 0; 4631 4632 if (!convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return make_parse_result(status_out_of_memory); 4633 4634 // delete original buffer if we performed a conversion 4635 if (own && buffer != contents && contents) global_deallocate(contents); 4636 4637 // parse 4638 xml_parse_result res = xml_parser::parse(buffer, length, _root, options); 4639 4640 // remember encoding 4641 res.encoding = buffer_encoding; 4642 4643 // grab onto buffer if it's our buffer, user is responsible for deallocating contens himself 4644 if (own || buffer != contents) _buffer = buffer; 4645 4646 return res; 4647 } 4648 4649 xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) 4650 { 4651 return load_buffer_impl(const_cast<void*>(contents), size, options, encoding, false, false); 4652 } 4653 4654 xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) 4655 { 4656 return load_buffer_impl(contents, size, options, encoding, true, false); 4657 } 4658 4659 xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) 4660 { 4661 return load_buffer_impl(contents, size, options, encoding, true, true); 4662 } 4663 4664 void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const 4665 { 4666 if (flags & format_write_bom) write_bom(writer, get_write_encoding(encoding)); 4667 4668 xml_buffered_writer buffered_writer(writer, encoding); 4669 4670 if (!(flags & format_no_declaration) && !has_declaration(*this)) 4671 { 4672 buffered_writer.write(PUGIXML_TEXT("<?xml version=\"1.0\"?>")); 6963 return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, const_cast<void*>(contents), size, options, encoding, false, false, &_buffer); 6964 } 6965 6966 PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding) 6967 { 6968 reset(); 6969 6970 return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, false, &_buffer); 6971 } 6972 6973 PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding) 6974 { 6975 reset(); 6976 6977 return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, true, &_buffer); 6978 } 6979 6980 PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const 6981 { 6982 impl::xml_buffered_writer buffered_writer(writer, encoding); 6983 6984 if ((flags & format_write_bom) && encoding != encoding_latin1) 6985 { 6986 // BOM always represents the codepoint U+FEFF, so just write it in native encoding 6987 #ifdef PUGIXML_WCHAR_MODE 6988 unsigned int bom = 0xfeff; 6989 buffered_writer.write(static_cast<wchar_t>(bom)); 6990 #else 6991 buffered_writer.write('\xef', '\xbb', '\xbf'); 6992 #endif 6993 } 6994 6995 if (!(flags & format_no_declaration) && !impl::has_declaration(_root)) 6996 { 6997 buffered_writer.write_string(PUGIXML_TEXT("<?xml version=\"1.0\"")); 6998 if (encoding == encoding_latin1) buffered_writer.write_string(PUGIXML_TEXT(" encoding=\"ISO-8859-1\"")); 6999 buffered_writer.write('?', '>'); 4673 7000 if (!(flags & format_raw)) buffered_writer.write('\n'); 4674 7001 } 4675 7002 4676 node_output(buffered_writer, *this, indent, flags, 0); 7003 impl::node_output(buffered_writer, _root, indent, flags, 0); 7004 7005 buffered_writer.flush(); 4677 7006 } 4678 7007 4679 7008 #ifndef PUGIXML_NO_STL 4680 void xml_document::save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const7009 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 4681 7010 { 4682 7011 xml_writer_stream writer(stream); … … 4685 7014 } 4686 7015 4687 void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags) const7016 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 4688 7017 { 4689 7018 xml_writer_stream writer(stream); … … 4693 7022 #endif 4694 7023 4695 bool xml_document::save_file(const char* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const 4696 { 4697 FILE* file = fopen(path, "wb"); 4698 if (!file) return false; 4699 4700 xml_writer_file writer(file); 4701 save(writer, indent, flags, encoding); 4702 4703 fclose(file); 4704 4705 return true; 4706 } 4707 4708 bool xml_document::save_file(const wchar_t* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const 4709 { 4710 FILE* file = open_file_wide(path, L"wb"); 4711 if (!file) return false; 4712 4713 xml_writer_file writer(file); 4714 save(writer, indent, flags, encoding); 4715 4716 fclose(file); 4717 4718 return true; 4719 } 4720 4721 xml_node xml_document::document_element() const 4722 { 7024 PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const 7025 { 7026 using impl::auto_deleter; // MSVC7 workaround 7027 auto_deleter<FILE> file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file); 7028 7029 return impl::save_file_impl(*this, file.data, indent, flags, encoding); 7030 } 7031 7032 PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const 7033 { 7034 using impl::auto_deleter; // MSVC7 workaround 7035 auto_deleter<FILE> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file); 7036 7037 return impl::save_file_impl(*this, file.data, indent, flags, encoding); 7038 } 7039 7040 PUGI__FN xml_node xml_document::document_element() const 7041 { 7042 assert(_root); 7043 4723 7044 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) 4724 if ( (i->header & xml_memory_page_type_mask) + 1== node_element)4725 4726 4727 4728 7045 if (PUGI__NODETYPE(i) == node_element) 7046 return xml_node(i); 7047 7048 return xml_node(); 7049 } 4729 7050 4730 7051 #ifndef PUGIXML_NO_STL 4731 std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)7052 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) 4732 7053 { 4733 7054 assert(str); 4734 7055 4735 return as_utf8_impl(str, wcslen(str));4736 } 4737 4738 std::string PUGIXML_FUNCTION as_utf8(const std::wstring& str)4739 { 4740 returnas_utf8_impl(str.c_str(), str.size());4741 } 4742 4743 std::wstringPUGIXML_FUNCTION as_wide(const char* str)7056 return impl::as_utf8_impl(str, impl::strlength_wide(str)); 7057 } 7058 7059 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str) 7060 { 7061 return impl::as_utf8_impl(str.c_str(), str.size()); 7062 } 7063 7064 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str) 4744 7065 { 4745 7066 assert(str); 4746 7067 4747 returnas_wide_impl(str, strlen(str));4748 } 4749 4750 std::wstringPUGIXML_FUNCTION as_wide(const std::string& str)4751 { 4752 returnas_wide_impl(str.c_str(), str.size());7068 return impl::as_wide_impl(str, strlen(str)); 7069 } 7070 7071 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str) 7072 { 7073 return impl::as_wide_impl(str.c_str(), str.size()); 4753 7074 } 4754 7075 #endif 4755 7076 4756 4757 4758 global_allocate = allocate;4759 global_deallocate = deallocate;4760 4761 4762 4763 4764 return global_allocate;4765 4766 4767 4768 4769 return global_deallocate;4770 7077 PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate) 7078 { 7079 impl::xml_memory::allocate = allocate; 7080 impl::xml_memory::deallocate = deallocate; 7081 } 7082 7083 PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function() 7084 { 7085 return impl::xml_memory::allocate; 7086 } 7087 7088 PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function() 7089 { 7090 return impl::xml_memory::deallocate; 7091 } 4771 7092 } 4772 7093 … … 4775 7096 { 4776 7097 // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier) 4777 std::bidirectional_iterator_tag _Iter_cat(constxml_node_iterator&)7098 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&) 4778 7099 { 4779 7100 return std::bidirectional_iterator_tag(); 4780 7101 } 4781 7102 4782 std::bidirectional_iterator_tag _Iter_cat(const xml_attribute_iterator&) 7103 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&) 7104 { 7105 return std::bidirectional_iterator_tag(); 7106 } 7107 7108 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&) 4783 7109 { 4784 7110 return std::bidirectional_iterator_tag(); … … 4791 7117 { 4792 7118 // Workarounds for (non-standard) iterator category detection 4793 std::bidirectional_iterator_tag __iterator_category(constxml_node_iterator&)7119 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&) 4794 7120 { 4795 7121 return std::bidirectional_iterator_tag(); 4796 7122 } 4797 7123 4798 std::bidirectional_iterator_tag __iterator_category(const xml_attribute_iterator&) 7124 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&) 7125 { 7126 return std::bidirectional_iterator_tag(); 7127 } 7128 7129 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&) 4799 7130 { 4800 7131 return std::bidirectional_iterator_tag(); … … 4804 7135 4805 7136 #ifndef PUGIXML_NO_XPATH 4806 4807 7137 // STL replacements 4808 namespace 4809 { 7138 PUGI__NS_BEGIN 4810 7139 struct equal_to 4811 7140 { … … 4860 7189 template <typename I> void reverse(I begin, I end) 4861 7190 { 4862 while ( begin + 1 < end) swap(*begin++, *--end);7191 while (end - begin > 1) swap(*begin++, *--end); 4863 7192 } 4864 7193 … … 4866 7195 { 4867 7196 // fast skip head 4868 while ( begin + 1 < end&& *begin != *(begin + 1)) begin++;7197 while (end - begin > 1 && *begin != *(begin + 1)) begin++; 4869 7198 4870 7199 if (begin == end) return begin; 4871 7200 4872 7201 // last written element 4873 I write = begin++; 7202 I write = begin++; 4874 7203 4875 7204 // merge unique elements … … 5031 7360 if (begin != end) insertion_sort(begin, end, pred, &*begin); 5032 7361 } 5033 } 7362 PUGI__NS_END 5034 7363 5035 7364 // Allocator used for AST and evaluation stacks 5036 namespace 5037 { 7365 PUGI__NS_BEGIN 7366 static const size_t xpath_memory_page_size = 7367 #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE 7368 PUGIXML_MEMORY_XPATH_PAGE_SIZE 7369 #else 7370 4096 7371 #endif 7372 ; 7373 7374 static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*); 7375 5038 7376 struct xpath_memory_block 5039 { 7377 { 5040 7378 xpath_memory_block* next; 5041 5042 char data[4096]; 7379 size_t capacity; 7380 7381 union 7382 { 7383 char data[xpath_memory_page_size]; 7384 double alignment; 7385 }; 5043 7386 }; 5044 7387 5045 7388 class xpath_allocator 5046 7389 { … … 5059 7402 #endif 5060 7403 } 5061 7404 5062 7405 void* allocate_nothrow(size_t size) 5063 7406 { 5064 const size_t block_capacity = sizeof(_root->data); 5065 5066 // align size so that we're able to store pointers in subsequent blocks 5067 size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); 5068 5069 if (_root_size + size <= block_capacity) 5070 { 5071 void* buf = _root->data + _root_size; 7407 // round size up to block alignment boundary 7408 size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); 7409 7410 if (_root_size + size <= _root->capacity) 7411 { 7412 void* buf = &_root->data[0] + _root_size; 5072 7413 _root_size += size; 5073 7414 return buf; … … 5075 7416 else 5076 7417 { 5077 size_t block_data_size = (size > block_capacity) ? size : block_capacity; 5078 size_t block_size = block_data_size + offsetof(xpath_memory_block, data); 5079 5080 xpath_memory_block* block = static_cast<xpath_memory_block*>(global_allocate(block_size)); 7418 // make sure we have at least 1/4th of the page free after allocation to satisfy subsequent allocation requests 7419 size_t block_capacity_base = sizeof(_root->data); 7420 size_t block_capacity_req = size + block_capacity_base / 4; 7421 size_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req; 7422 7423 size_t block_size = block_capacity + offsetof(xpath_memory_block, data); 7424 7425 xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size)); 5081 7426 if (!block) return 0; 5082 7427 5083 7428 block->next = _root; 5084 7429 block->capacity = block_capacity; 7430 5085 7431 _root = block; 5086 7432 _root_size = size; 5087 7433 5088 7434 return block->data; 5089 7435 } … … 5109 7455 void* reallocate(void* ptr, size_t old_size, size_t new_size) 5110 7456 { 5111 // align size so that we're able to store pointers in subsequent blocks5112 old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*)- 1);5113 new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*)- 1);7457 // round size up to block alignment boundary 7458 old_size = (old_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); 7459 new_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); 5114 7460 5115 7461 // we can only reallocate the last object 5116 assert(ptr == 0 || static_cast<char*>(ptr) + old_size == _root->data+ _root_size);7462 assert(ptr == 0 || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size); 5117 7463 5118 7464 // adjust root size so that we have not allocated the object at all … … 5129 7475 { 5130 7476 // copy old data 5131 assert(new_size > old_size);7477 assert(new_size >= old_size); 5132 7478 memcpy(result, ptr, old_size); 5133 7479 … … 5143 7489 { 5144 7490 // deallocate the whole page, unless it was the first one 5145 global_deallocate(_root->next);7491 xml_memory::deallocate(_root->next); 5146 7492 _root->next = next; 5147 7493 } … … 5161 7507 xpath_memory_block* next = cur->next; 5162 7508 5163 global_deallocate(cur);7509 xml_memory::deallocate(cur); 5164 7510 5165 7511 cur = next; … … 5180 7526 xpath_memory_block* next = cur->next; 5181 7527 5182 global_deallocate(cur);7528 xml_memory::deallocate(cur); 5183 7529 5184 7530 cur = next; … … 5222 7568 { 5223 7569 blocks[0].next = blocks[1].next = 0; 7570 blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data); 5224 7571 5225 7572 stack.result = &result; … … 5237 7584 } 5238 7585 }; 5239 } 7586 PUGI__NS_END 5240 7587 5241 7588 // String class 5242 namespace 5243 { 7589 PUGI__NS_BEGIN 5244 7590 class xpath_string 5245 7591 { 5246 7592 const char_t* _buffer; 5247 7593 bool _uses_heap; 7594 size_t _length_heap; 5248 7595 5249 7596 static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc) … … 5258 7605 } 5259 7606 5260 static char_t* duplicate_string(const char_t* string, xpath_allocator* alloc) 5261 { 5262 return duplicate_string(string, strlength(string), alloc); 7607 xpath_string(const char_t* buffer, bool uses_heap_, size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap) 7608 { 5263 7609 } 5264 7610 5265 7611 public: 5266 xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false) 5267 { 5268 } 5269 5270 explicit xpath_string(const char_t* str, xpath_allocator* alloc) 5271 { 5272 bool empty = (*str == 0); 5273 5274 _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(str, alloc); 5275 _uses_heap = !empty; 5276 } 5277 5278 explicit xpath_string(const char_t* str, bool use_heap): _buffer(str), _uses_heap(use_heap) 5279 { 5280 } 5281 5282 xpath_string(const char_t* begin, const char_t* end, xpath_allocator* alloc) 7612 static xpath_string from_const(const char_t* str) 7613 { 7614 return xpath_string(str, false, 0); 7615 } 7616 7617 static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end) 7618 { 7619 assert(begin <= end && *end == 0); 7620 7621 return xpath_string(begin, true, static_cast<size_t>(end - begin)); 7622 } 7623 7624 static xpath_string from_heap(const char_t* begin, const char_t* end, xpath_allocator* alloc) 5283 7625 { 5284 7626 assert(begin <= end); 5285 7627 5286 bool empty = (begin == end); 5287 5288 _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast<size_t>(end - begin), alloc); 5289 _uses_heap = !empty; 7628 size_t length = static_cast<size_t>(end - begin); 7629 7630 return length == 0 ? xpath_string() : xpath_string(duplicate_string(begin, length, alloc), true, length); 7631 } 7632 7633 xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false), _length_heap(0) 7634 { 5290 7635 } 5291 7636 … … 5303 7648 { 5304 7649 // need to make heap copy 5305 size_t target_length = strlength(_buffer);5306 size_t source_length = strlength(o._buffer);5307 size_t length = target_length + source_length;7650 size_t target_length = length(); 7651 size_t source_length = o.length(); 7652 size_t result_length = target_length + source_length; 5308 7653 5309 7654 // allocate new buffer 5310 char_t* result = static_cast<char_t*>(alloc->reallocate(_uses_heap ? const_cast<char_t*>(_buffer) : 0, (target_length + 1) * sizeof(char_t), ( length + 1) * sizeof(char_t)));7655 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))); 5311 7656 assert(result); 5312 7657 … … 5316 7661 // append second string to the new buffer 5317 7662 memcpy(result + target_length, o._buffer, source_length * sizeof(char_t)); 5318 result[ length] = 0;7663 result[result_length] = 0; 5319 7664 5320 7665 // finalize 5321 7666 _buffer = result; 5322 7667 _uses_heap = true; 7668 _length_heap = result_length; 5323 7669 } 5324 7670 } … … 5331 7677 size_t length() const 5332 7678 { 5333 return strlength(_buffer);5334 } 5335 7679 return _uses_heap ? _length_heap : strlength(_buffer); 7680 } 7681 5336 7682 char_t* data(xpath_allocator* alloc) 5337 7683 { … … 5339 7685 if (!_uses_heap) 5340 7686 { 5341 _buffer = duplicate_string(_buffer, alloc); 7687 size_t length_ = strlength(_buffer); 7688 7689 _buffer = duplicate_string(_buffer, length_, alloc); 5342 7690 _uses_heap = true; 7691 _length_heap = length_; 5343 7692 } 5344 7693 … … 5366 7715 } 5367 7716 }; 5368 5369 xpath_string xpath_string_const(const char_t* str) 5370 { 5371 return xpath_string(str, false); 5372 } 5373 } 5374 5375 namespace 5376 { 5377 bool starts_with(const char_t* string, const char_t* pattern) 7717 PUGI__NS_END 7718 7719 PUGI__NS_BEGIN 7720 PUGI__FN bool starts_with(const char_t* string, const char_t* pattern) 5378 7721 { 5379 7722 while (*pattern && *string == *pattern) … … 5386 7729 } 5387 7730 5388 const char_t* find_char(const char_t* s, char_t c)7731 PUGI__FN const char_t* find_char(const char_t* s, char_t c) 5389 7732 { 5390 7733 #ifdef PUGIXML_WCHAR_MODE … … 5395 7738 } 5396 7739 5397 const char_t* find_substring(const char_t* s, const char_t* p)7740 PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p) 5398 7741 { 5399 7742 #ifdef PUGIXML_WCHAR_MODE … … 5406 7749 5407 7750 // Converts symbol to lower case, if it is an ASCII one 5408 char_t tolower_ascii(char_t ch)7751 PUGI__FN char_t tolower_ascii(char_t ch) 5409 7752 { 5410 7753 return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch; 5411 7754 } 5412 7755 5413 xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)7756 PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc) 5414 7757 { 5415 7758 if (na.attribute()) 5416 return xpath_string _const(na.attribute().value());7759 return xpath_string::from_const(na.attribute().value()); 5417 7760 else 5418 7761 { 5419 const xml_node&n = na.node();7762 xml_node n = na.node(); 5420 7763 5421 7764 switch (n.type()) … … 5425 7768 case node_comment: 5426 7769 case node_pi: 5427 return xpath_string _const(n.value());5428 7770 return xpath_string::from_const(n.value()); 7771 5429 7772 case node_document: 5430 7773 case node_element: … … 5432 7775 xpath_string result; 5433 7776 7777 // element nodes can have value if parse_embed_pcdata was used 7778 if (n.value()[0]) 7779 result.append(xpath_string::from_const(n.value()), alloc); 7780 5434 7781 xml_node cur = n.first_child(); 5435 7782 5436 7783 while (cur && cur != n) 5437 7784 { 5438 7785 if (cur.type() == node_pcdata || cur.type() == node_cdata) 5439 result.append(xpath_string _const(cur.value()), alloc);7786 result.append(xpath_string::from_const(cur.value()), alloc); 5440 7787 5441 7788 if (cur.first_child()) … … 5451 7798 } 5452 7799 } 5453 7800 5454 7801 return result; 5455 7802 } 5456 7803 5457 7804 default: 5458 7805 return xpath_string(); … … 5460 7807 } 5461 7808 } 5462 5463 unsigned int node_height(xml_node n) 5464 { 5465 unsigned int result = 0; 5466 5467 while (n) 5468 { 5469 ++result; 5470 n = n.parent(); 5471 } 5472 5473 return result; 5474 } 5475 5476 bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh) 5477 { 5478 // normalize heights 5479 for (unsigned int i = rh; i < lh; i++) ln = ln.parent(); 5480 for (unsigned int j = lh; j < rh; j++) rn = rn.parent(); 5481 7809 7810 PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) 7811 { 7812 assert(ln->parent == rn->parent); 7813 7814 // there is no common ancestor (the shared parent is null), nodes are from different documents 7815 if (!ln->parent) return ln < rn; 7816 7817 // determine sibling order 7818 xml_node_struct* ls = ln; 7819 xml_node_struct* rs = rn; 7820 7821 while (ls && rs) 7822 { 7823 if (ls == rn) return true; 7824 if (rs == ln) return false; 7825 7826 ls = ls->next_sibling; 7827 rs = rs->next_sibling; 7828 } 7829 7830 // if rn sibling chain ended ln must be before rn 7831 return !rs; 7832 } 7833 7834 PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) 7835 { 7836 // find common ancestor at the same depth, if any 7837 xml_node_struct* lp = ln; 7838 xml_node_struct* rp = rn; 7839 7840 while (lp && rp && lp->parent != rp->parent) 7841 { 7842 lp = lp->parent; 7843 rp = rp->parent; 7844 } 7845 7846 // parents are the same! 7847 if (lp && rp) return node_is_before_sibling(lp, rp); 7848 7849 // nodes are at different depths, need to normalize heights 7850 bool left_higher = !lp; 7851 7852 while (lp) 7853 { 7854 lp = lp->parent; 7855 ln = ln->parent; 7856 } 7857 7858 while (rp) 7859 { 7860 rp = rp->parent; 7861 rn = rn->parent; 7862 } 7863 5482 7864 // one node is the ancestor of the other 5483 if (ln == rn) return lh < rh;5484 5485 // find common ancestor 5486 while (ln.parent() != rn.parent())5487 5488 ln = ln.parent();5489 rn = rn.parent();5490 5491 5492 // there is no common ancestor (the shared parent is null), nodes are from different documents5493 if (!ln.parent()) return ln < rn;5494 5495 // determine sibling order5496 for (; ln; ln = ln.next_sibling()) 5497 if (ln == rn) 5498 return true; 5499 5500 return false; 5501 } 5502 5503 bool node_is_ancestor(xml_node parent, xml_node node) 5504 { 5505 while (node && node != parent) node = node.parent(); 5506 5507 return parent && node == parent; 5508 } 5509 5510 const void* document_order(const xpath_node& xnode) 5511 { 5512 xml_node_struct* node = xnode.node().internal_object(); 5513 5514 if (node) 5515 { 5516 if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0) return node->name; 5517 if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0) return node->value;5518 return 0; 5519 } 5520 5521 xml_attribute_struct* attr = xnode.attribute().internal_object(); 5522 5523 if (attr) 5524 { 5525 if ((attr->header & xml_memory_page_name_allocated_mask) == 0) return attr->name; 5526 if ((attr->header & xml_memory_page_value_allocated_mask) == 0) return attr->value; 5527 5528 7865 if (ln == rn) return left_higher; 7866 7867 // find common ancestor... again 7868 while (ln->parent != rn->parent) 7869 { 7870 ln = ln->parent; 7871 rn = rn->parent; 7872 } 7873 7874 return node_is_before_sibling(ln, rn); 7875 } 7876 7877 PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node) 7878 { 7879 while (node && node != parent) node = node->parent; 7880 7881 return parent && node == parent; 7882 } 7883 7884 PUGI__FN const void* document_buffer_order(const xpath_node& xnode) 7885 { 7886 xml_node_struct* node = xnode.node().internal_object(); 7887 7888 if (node) 7889 { 7890 if ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0) 7891 { 7892 if (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return node->name; 7893 if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value; 7894 } 7895 7896 return 0; 7897 } 7898 7899 xml_attribute_struct* attr = xnode.attribute().internal_object(); 7900 7901 if (attr) 7902 { 7903 if ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0) 7904 { 7905 if ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return attr->name; 7906 if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value; 7907 } 7908 7909 return 0; 7910 } 5529 7911 5530 7912 return 0; 5531 5532 7913 } 7914 5533 7915 struct document_order_comparator 5534 7916 { … … 5536 7918 { 5537 7919 // optimized document order based check 5538 const void* lo = document_ order(lhs);5539 const void* ro = document_ order(rhs);7920 const void* lo = document_buffer_order(lhs); 7921 const void* ro = document_buffer_order(rhs); 5540 7922 5541 7923 if (lo && ro) return lo < ro; 5542 7924 5543 7925 // slow comparison 5544 7926 xml_node ln = lhs.node(), rn = rhs.node(); 5545 7927 … … 5551 7933 { 5552 7934 // determine sibling order 5553 5554 5555 5556 5557 5558 } 5559 7935 for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) 7936 if (a == rhs.attribute()) 7937 return true; 7938 7939 return false; 7940 } 7941 5560 7942 // compare attribute parents 5561 7943 ln = lhs.parent(); … … 5566 7948 // attributes go after the parent element 5567 7949 if (lhs.parent() == rhs.node()) return false; 5568 7950 5569 7951 ln = lhs.parent(); 5570 7952 } … … 5573 7955 // attributes go after the parent element 5574 7956 if (rhs.parent() == lhs.node()) return true; 5575 7957 5576 7958 rn = rhs.parent(); 5577 7959 } 5578 7960 5579 7961 if (ln == rn) return false; 5580 5581 unsigned int lh = node_height(ln); 5582 unsigned int rh = node_height(rn); 5583 5584 return node_is_before(ln, lh, rn, rh); 7962 7963 if (!ln || !rn) return ln < rn; 7964 7965 return node_is_before(ln.internal_object(), rn.internal_object()); 5585 7966 } 5586 7967 }; … … 5594 7975 } 5595 7976 }; 5596 5597 double gen_nan()7977 7978 PUGI__FN double gen_nan() 5598 7979 { 5599 7980 #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) 5600 union { float f; int32_t i; } u[sizeof(float) == sizeof(int32_t) ? 1 : -1]; 5601 u[0].i = 0x7fc00000; 5602 return u[0].f; 7981 PUGI__STATIC_ASSERT(sizeof(float) == sizeof(uint32_t)); 7982 typedef uint32_t UI; // BCC5 workaround 7983 union { float f; UI i; } u; 7984 u.i = 0x7fc00000; 7985 return u.f; 5603 7986 #else 5604 7987 // fallback … … 5607 7990 #endif 5608 7991 } 5609 5610 bool is_nan(double value)5611 { 5612 #if defined( _MSC_VER) || defined(__BORLANDC__)7992 7993 PUGI__FN bool is_nan(double value) 7994 { 7995 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) 5613 7996 return !!_isnan(value); 5614 7997 #elif defined(fpclassify) && defined(FP_NAN) … … 5620 8003 #endif 5621 8004 } 5622 5623 const char_t* convert_number_to_string_special(double value)5624 { 5625 #if defined( _MSC_VER) || defined(__BORLANDC__)8005 8006 PUGI__FN const char_t* convert_number_to_string_special(double value) 8007 { 8008 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) 5626 8009 if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; 5627 8010 if (_isnan(value)) return PUGIXML_TEXT("NaN"); 5628 return PUGIXML_TEXT("-Infinity") + (value > 0);8011 return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); 5629 8012 #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) 5630 8013 switch (fpclassify(value)) … … 5634 8017 5635 8018 case FP_INFINITE: 5636 return PUGIXML_TEXT("-Infinity") + (value > 0);8019 return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); 5637 8020 5638 8021 case FP_ZERO: … … 5648 8031 if (v == 0) return PUGIXML_TEXT("0"); 5649 8032 if (v != v) return PUGIXML_TEXT("NaN"); 5650 if (v * 2 == v) return PUGIXML_TEXT("-Infinity") + (value > 0);8033 if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); 5651 8034 return 0; 5652 8035 #endif 5653 8036 } 5654 5655 bool convert_number_to_boolean(double value)8037 8038 PUGI__FN bool convert_number_to_boolean(double value) 5656 8039 { 5657 8040 return (value != 0 && !is_nan(value)); 5658 8041 } 5659 5660 void truncate_zeros(char* begin, char* end)8042 8043 PUGI__FN void truncate_zeros(char* begin, char* end) 5661 8044 { 5662 8045 while (begin != end && end[-1] == '0') end--; … … 5666 8049 5667 8050 // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent 5668 #if defined( _MSC_VER) && _MSC_VER >= 14005669 void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)8051 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE) 8052 PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) 5670 8053 { 5671 8054 // get base values … … 5681 8064 } 5682 8065 #else 5683 void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)8066 PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent) 5684 8067 { 5685 8068 // get a scientific notation value with IEEE DBL_DIG decimals … … 5712 8095 #endif 5713 8096 5714 xpath_string convert_number_to_string(double value, xpath_allocator* alloc)8097 PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc) 5715 8098 { 5716 8099 // try special number conversion 5717 8100 const char_t* special = convert_number_to_string_special(value); 5718 if (special) return xpath_string _const(special);8101 if (special) return xpath_string::from_const(special); 5719 8102 5720 8103 // get mantissa + exponent form 5721 char mantissa_buffer[ 64];8104 char mantissa_buffer[32]; 5722 8105 5723 8106 char* mantissa; … … 5725 8108 convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent); 5726 8109 8110 // allocate a buffer of suitable length for the number 8111 size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4; 8112 char_t* result = static_cast<char_t*>(alloc->allocate(sizeof(char_t) * result_size)); 8113 assert(result); 8114 5727 8115 // make the number! 5728 char_t result[512];5729 8116 char_t* s = result; 5730 8117 … … 5741 8128 while (exponent > 0) 5742 8129 { 5743 assert(*mantissa == 0 || (unsigned)(*mantissa- '0') <= 9);8130 assert(*mantissa == 0 || static_cast<unsigned int>(static_cast<unsigned int>(*mantissa) - '0') <= 9); 5744 8131 *s++ = *mantissa ? *mantissa++ : '0'; 5745 8132 exponent--; … … 5763 8150 while (*mantissa) 5764 8151 { 5765 assert( (unsigned)(*mantissa - '0') <= 9);8152 assert(static_cast<unsigned int>(*mantissa - '0') <= 9); 5766 8153 *s++ = *mantissa++; 5767 8154 } … … 5769 8156 5770 8157 // zero-terminate 5771 assert(s < result + sizeof(result) / sizeof(result[0]));8158 assert(s < result + result_size); 5772 8159 *s = 0; 5773 8160 5774 return xpath_string (result, alloc);5775 } 5776 5777 bool check_string_to_number_format(const char_t* string)8161 return xpath_string::from_heap_preallocated(result, s); 8162 } 8163 8164 PUGI__FN bool check_string_to_number_format(const char_t* string) 5778 8165 { 5779 8166 // parse leading whitespace 5780 while ( IS_CHARTYPE(*string, ct_space)) ++string;8167 while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; 5781 8168 5782 8169 // parse sign … … 5786 8173 5787 8174 // if there is no integer part, there should be a decimal part with at least one digit 5788 if (! IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !IS_CHARTYPEX(string[1], ctx_digit))) return false;8175 if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false; 5789 8176 5790 8177 // parse integer part 5791 while ( IS_CHARTYPEX(*string, ctx_digit)) ++string;8178 while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; 5792 8179 5793 8180 // parse decimal part … … 5796 8183 ++string; 5797 8184 5798 while ( IS_CHARTYPEX(*string, ctx_digit)) ++string;8185 while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string; 5799 8186 } 5800 8187 5801 8188 // parse trailing whitespace 5802 while ( IS_CHARTYPE(*string, ct_space)) ++string;8189 while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; 5803 8190 5804 8191 return *string == 0; 5805 8192 } 5806 8193 5807 double convert_string_to_number(const char_t* string)8194 PUGI__FN double convert_string_to_number(const char_t* string) 5808 8195 { 5809 8196 // check string format … … 5814 8201 return wcstod(string, 0); 5815 8202 #else 5816 return atof(string);8203 return strtod(string, 0); 5817 8204 #endif 5818 8205 } 5819 8206 5820 bool convert_string_to_number(const char_t* begin, const char_t* end, double* out_result) 5821 { 5822 char_t buffer[32]; 5823 8207 PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result) 8208 { 5824 8209 size_t length = static_cast<size_t>(end - begin); 5825 8210 char_t* scratch = buffer; … … 5828 8213 { 5829 8214 // need to make dummy on-heap copy 5830 scratch = static_cast<char_t*>( global_allocate((length + 1) * sizeof(char_t)));8215 scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t))); 5831 8216 if (!scratch) return false; 5832 8217 } … … 5839 8224 5840 8225 // free dummy buffer 5841 if (scratch != buffer) global_deallocate(scratch);8226 if (scratch != buffer) xml_memory::deallocate(scratch); 5842 8227 5843 8228 return true; 5844 8229 } 5845 5846 double round_nearest(double value)8230 8231 PUGI__FN double round_nearest(double value) 5847 8232 { 5848 8233 return floor(value + 0.5); 5849 8234 } 5850 8235 5851 double round_nearest_nzero(double value)8236 PUGI__FN double round_nearest_nzero(double value) 5852 8237 { 5853 8238 // same as round_nearest, but returns -0 for [-0.5, -0] … … 5855 8240 return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); 5856 8241 } 5857 5858 const char_t* qualified_name(const xpath_node& node)8242 8243 PUGI__FN const char_t* qualified_name(const xpath_node& node) 5859 8244 { 5860 8245 return node.attribute() ? node.attribute().name() : node.node().name(); 5861 8246 } 5862 5863 const char_t* local_name(const xpath_node& node)8247 8248 PUGI__FN const char_t* local_name(const xpath_node& node) 5864 8249 { 5865 8250 const char_t* name = qualified_name(node); 5866 8251 const char_t* p = find_char(name, ':'); 5867 8252 5868 8253 return p ? p + 1 : name; 5869 8254 } … … 5882 8267 } 5883 8268 5884 bool operator()( const xml_attribute&a) const8269 bool operator()(xml_attribute a) const 5885 8270 { 5886 8271 const char_t* name = a.name(); … … 5892 8277 }; 5893 8278 5894 const char_t* namespace_uri(const xml_node&node)8279 PUGI__FN const char_t* namespace_uri(xml_node node) 5895 8280 { 5896 8281 namespace_uri_predicate pred = node.name(); 5897 8282 5898 8283 xml_node p = node; 5899 8284 5900 8285 while (p) 5901 8286 { 5902 8287 xml_attribute a = p.find_attribute(pred); 5903 8288 5904 8289 if (a) return a.value(); 5905 8290 5906 8291 p = p.parent(); 5907 8292 } 5908 8293 5909 8294 return PUGIXML_TEXT(""); 5910 8295 } 5911 8296 5912 const char_t* namespace_uri(const xml_attribute& attr, const xml_node&parent)8297 PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) 5913 8298 { 5914 8299 namespace_uri_predicate pred = attr.name(); 5915 8300 5916 8301 // Default namespace does not apply to attributes 5917 8302 if (!pred.prefix) return PUGIXML_TEXT(""); 5918 8303 5919 8304 xml_node p = parent; 5920 8305 5921 8306 while (p) 5922 8307 { 5923 8308 xml_attribute a = p.find_attribute(pred); 5924 8309 5925 8310 if (a) return a.value(); 5926 8311 5927 8312 p = p.parent(); 5928 8313 } 5929 8314 5930 8315 return PUGIXML_TEXT(""); 5931 8316 } 5932 8317 5933 const char_t* namespace_uri(const xpath_node& node)8318 PUGI__FN const char_t* namespace_uri(const xpath_node& node) 5934 8319 { 5935 8320 return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node()); 5936 8321 } 5937 8322 5938 voidnormalize_space(char_t* buffer)8323 PUGI__FN char_t* normalize_space(char_t* buffer) 5939 8324 { 5940 8325 char_t* write = buffer; … … 5944 8329 char_t ch = *it++; 5945 8330 5946 if ( IS_CHARTYPE(ch, ct_space))8331 if (PUGI__IS_CHARTYPE(ch, ct_space)) 5947 8332 { 5948 8333 // replace whitespace sequence with single space 5949 while ( IS_CHARTYPE(*it, ct_space)) it++;8334 while (PUGI__IS_CHARTYPE(*it, ct_space)) it++; 5950 8335 5951 8336 // avoid leading spaces … … 5956 8341 5957 8342 // remove trailing space 5958 if (write != buffer && IS_CHARTYPE(write[-1], ct_space)) write--;8343 if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--; 5959 8344 5960 8345 // zero-terminate 5961 8346 *write = 0; 5962 } 5963 5964 void translate(char_t* buffer, const char_t* from, const char_t* to)5965 { 5966 size_t to_length = strlength(to);5967 8347 8348 return write; 8349 } 8350 8351 PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length) 8352 { 5968 8353 char_t* write = buffer; 5969 8354 5970 8355 while (*buffer) 5971 8356 { 5972 DMC_VOLATILE char_t ch = *buffer++;8357 PUGI__DMC_VOLATILE char_t ch = *buffer++; 5973 8358 5974 8359 const char_t* pos = find_char(from, ch); … … 5982 8367 // zero-terminate 5983 8368 *write = 0; 8369 8370 return write; 8371 } 8372 8373 PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to) 8374 { 8375 unsigned char table[128] = {0}; 8376 8377 while (*from) 8378 { 8379 unsigned int fc = static_cast<unsigned int>(*from); 8380 unsigned int tc = static_cast<unsigned int>(*to); 8381 8382 if (fc >= 128 || tc >= 128) 8383 return 0; 8384 8385 // code=128 means "skip character" 8386 if (!table[fc]) 8387 table[fc] = static_cast<unsigned char>(tc ? tc : 128); 8388 8389 from++; 8390 if (tc) to++; 8391 } 8392 8393 for (int i = 0; i < 128; ++i) 8394 if (!table[i]) 8395 table[i] = static_cast<unsigned char>(i); 8396 8397 void* result = alloc->allocate_nothrow(sizeof(table)); 8398 8399 if (result) 8400 { 8401 memcpy(result, table, sizeof(table)); 8402 } 8403 8404 return static_cast<unsigned char*>(result); 8405 } 8406 8407 PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table) 8408 { 8409 char_t* write = buffer; 8410 8411 while (*buffer) 8412 { 8413 char_t ch = *buffer++; 8414 unsigned int index = static_cast<unsigned int>(ch); 8415 8416 if (index < 128) 8417 { 8418 unsigned char code = table[index]; 8419 8420 // code=128 means "skip character" (table size is 128 so 128 can be a special value) 8421 // this code skips these characters without extra branches 8422 *write = static_cast<char_t>(code); 8423 write += 1 - (code >> 7); 8424 } 8425 else 8426 { 8427 *write++ = ch; 8428 } 8429 } 8430 8431 // zero-terminate 8432 *write = 0; 8433 8434 return write; 8435 } 8436 8437 inline bool is_xpath_attribute(const char_t* name) 8438 { 8439 return !(starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')); 5984 8440 } 5985 8441 5986 8442 struct xpath_variable_boolean: xpath_variable 5987 8443 { 5988 xpath_variable_boolean(): value(false)8444 xpath_variable_boolean(): xpath_variable(xpath_type_boolean), value(false) 5989 8445 { 5990 8446 } … … 5996 8452 struct xpath_variable_number: xpath_variable 5997 8453 { 5998 xpath_variable_number(): value(0)8454 xpath_variable_number(): xpath_variable(xpath_type_number), value(0) 5999 8455 { 6000 8456 } … … 6006 8462 struct xpath_variable_string: xpath_variable 6007 8463 { 6008 xpath_variable_string(): value(0)8464 xpath_variable_string(): xpath_variable(xpath_type_string), value(0) 6009 8465 { 6010 8466 } … … 6012 8468 ~xpath_variable_string() 6013 8469 { 6014 if (value) global_deallocate(value);8470 if (value) xml_memory::deallocate(value); 6015 8471 } 6016 8472 … … 6021 8477 struct xpath_variable_node_set: xpath_variable 6022 8478 { 8479 xpath_variable_node_set(): xpath_variable(xpath_type_node_set) 8480 { 8481 } 8482 6023 8483 xpath_node_set value; 6024 8484 char_t name[1]; 6025 8485 }; 6026 8486 6027 const xpath_node_set dummy_node_set;6028 6029 unsigned int hash_string(const char_t* str)8487 static const xpath_node_set dummy_node_set; 8488 8489 PUGI__FN unsigned int hash_string(const char_t* str) 6030 8490 { 6031 8491 // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time) … … 6038 8498 result ^= result >> 6; 6039 8499 } 6040 8500 6041 8501 result += result << 3; 6042 8502 result ^= result >> 11; 6043 8503 result += result << 15; 6044 8504 6045 8505 return result; 6046 8506 } 6047 8507 6048 template <typename T> T* new_xpath_variable(const char_t* name)8508 template <typename T> PUGI__FN T* new_xpath_variable(const char_t* name) 6049 8509 { 6050 8510 size_t length = strlength(name); … … 6052 8512 6053 8513 // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters 6054 void* memory = global_allocate(sizeof(T) + length * sizeof(char_t));8514 void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t)); 6055 8515 if (!memory) return 0; 6056 8516 … … 6062 8522 } 6063 8523 6064 xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)8524 PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name) 6065 8525 { 6066 8526 switch (type) … … 6083 8543 } 6084 8544 6085 template <typename T> void delete_xpath_variable(T* var)8545 template <typename T> PUGI__FN void delete_xpath_variable(T* var) 6086 8546 { 6087 8547 var->~T(); 6088 global_deallocate(var);6089 } 6090 6091 void delete_xpath_variable(xpath_value_type type, xpath_variable* var)8548 xml_memory::deallocate(var); 8549 } 8550 8551 PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var) 6092 8552 { 6093 8553 switch (type) … … 6110 8570 6111 8571 default: 6112 assert(!"Invalid variable type"); 6113 } 6114 } 6115 6116 xpath_variable* get_variable(xpath_variable_set* set, const char_t* begin, const char_t* end) 6117 { 6118 char_t buffer[32]; 6119 8572 assert(false && "Invalid variable type"); 8573 } 8574 } 8575 8576 PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs) 8577 { 8578 switch (rhs->type()) 8579 { 8580 case xpath_type_node_set: 8581 return lhs->set(static_cast<const xpath_variable_node_set*>(rhs)->value); 8582 8583 case xpath_type_number: 8584 return lhs->set(static_cast<const xpath_variable_number*>(rhs)->value); 8585 8586 case xpath_type_string: 8587 return lhs->set(static_cast<const xpath_variable_string*>(rhs)->value); 8588 8589 case xpath_type_boolean: 8590 return lhs->set(static_cast<const xpath_variable_boolean*>(rhs)->value); 8591 8592 default: 8593 assert(false && "Invalid variable type"); 8594 return false; 8595 } 8596 } 8597 8598 PUGI__FN bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end, xpath_variable** out_result) 8599 { 6120 8600 size_t length = static_cast<size_t>(end - begin); 6121 8601 char_t* scratch = buffer; … … 6124 8604 { 6125 8605 // need to make dummy on-heap copy 6126 scratch = static_cast<char_t*>( global_allocate((length + 1) * sizeof(char_t)));6127 if (!scratch) return 0;8606 scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t))); 8607 if (!scratch) return false; 6128 8608 } 6129 8609 … … 6132 8612 scratch[length] = 0; 6133 8613 6134 xpath_variable*result = set->get(scratch);8614 *out_result = set->get(scratch); 6135 8615 6136 8616 // free dummy buffer 6137 if (scratch != buffer) global_deallocate(scratch);6138 6139 return result;6140 } 6141 } 8617 if (scratch != buffer) xml_memory::deallocate(scratch); 8618 8619 return true; 8620 } 8621 PUGI__NS_END 6142 8622 6143 8623 // Internal node set class 6144 namespace 6145 { 6146 xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) 8624 PUGI__NS_BEGIN 8625 PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end) 8626 { 8627 if (end - begin < 2) 8628 return xpath_node_set::type_sorted; 8629 8630 document_order_comparator cmp; 8631 8632 bool first = cmp(begin[0], begin[1]); 8633 8634 for (const xpath_node* it = begin + 1; it + 1 < end; ++it) 8635 if (cmp(it[0], it[1]) != first) 8636 return xpath_node_set::type_unsorted; 8637 8638 return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse; 8639 } 8640 8641 PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev) 6147 8642 { 6148 8643 xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; … … 6150 8645 if (type == xpath_node_set::type_unsorted) 6151 8646 { 6152 sort(begin, end, document_order_comparator()); 6153 6154 type = xpath_node_set::type_sorted; 6155 } 6156 8647 xpath_node_set::type_t sorted = xpath_get_order(begin, end); 8648 8649 if (sorted == xpath_node_set::type_unsorted) 8650 { 8651 sort(begin, end, document_order_comparator()); 8652 8653 type = xpath_node_set::type_sorted; 8654 } 8655 else 8656 type = sorted; 8657 } 8658 6157 8659 if (type != order) reverse(begin, end); 6158 8660 6159 8661 return order; 6160 8662 } 6161 8663 6162 xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)8664 PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) 6163 8665 { 6164 8666 if (begin == end) return xpath_node(); … … 6176 8678 6177 8679 default: 6178 assert( !"Invalid node set type");8680 assert(false && "Invalid node set type"); 6179 8681 return xpath_node(); 6180 8682 } 6181 8683 } 8684 6182 8685 class xpath_node_set_raw 6183 8686 { … … 6218 8721 } 6219 8722 8723 void push_back_grow(const xpath_node& node, xpath_allocator* alloc); 8724 6220 8725 void push_back(const xpath_node& node, xpath_allocator* alloc) 6221 8726 { 6222 if (_end == _eos) 6223 { 6224 size_t capacity = static_cast<size_t>(_eos - _begin); 6225 6226 // get new capacity (1.5x rule) 6227 size_t new_capacity = capacity + capacity / 2 + 1; 6228 8727 if (_end != _eos) 8728 *_end++ = node; 8729 else 8730 push_back_grow(node, alloc); 8731 } 8732 8733 void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc) 8734 { 8735 if (begin_ == end_) return; 8736 8737 size_t size_ = static_cast<size_t>(_end - _begin); 8738 size_t capacity = static_cast<size_t>(_eos - _begin); 8739 size_t count = static_cast<size_t>(end_ - begin_); 8740 8741 if (size_ + count > capacity) 8742 { 6229 8743 // reallocate the old array or allocate a new one 6230 xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity* sizeof(xpath_node)));8744 xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node))); 6231 8745 assert(data); 6232 8746 6233 8747 // finalize 6234 8748 _begin = data; 6235 _end = data + capacity; 6236 _eos = data + new_capacity; 6237 } 6238 6239 *_end++ = node; 6240 } 6241 6242 void append(const xpath_node* begin, const xpath_node* end, xpath_allocator* alloc) 6243 { 6244 size_t size = static_cast<size_t>(_end - _begin); 6245 size_t capacity = static_cast<size_t>(_eos - _begin); 6246 size_t count = static_cast<size_t>(end - begin); 6247 6248 if (size + count > capacity) 6249 { 6250 // reallocate the old array or allocate a new one 6251 xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size + count) * sizeof(xpath_node))); 6252 assert(data); 6253 6254 // finalize 6255 _begin = data; 6256 _end = data + size; 6257 _eos = data + size + count; 6258 } 6259 6260 memcpy(_end, begin, count * sizeof(xpath_node)); 8749 _end = data + size_; 8750 _eos = data + size_ + count; 8751 } 8752 8753 memcpy(_end, begin_, count * sizeof(xpath_node)); 6261 8754 _end += count; 6262 8755 } … … 6278 8771 if (_type == xpath_node_set::type_unsorted) 6279 8772 sort(_begin, _end, duplicate_comparator()); 6280 8773 6281 8774 _end = unique(_begin, _end); 6282 8775 } … … 6287 8780 } 6288 8781 6289 void set_type(xpath_node_set::type_t type)6290 { 6291 _type = type;8782 void set_type(xpath_node_set::type_t value) 8783 { 8784 _type = value; 6292 8785 } 6293 8786 }; 6294 } 6295 6296 namespace 6297 { 8787 8788 PUGI__FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc) 8789 { 8790 size_t capacity = static_cast<size_t>(_eos - _begin); 8791 8792 // get new capacity (1.5x rule) 8793 size_t new_capacity = capacity + capacity / 2 + 1; 8794 8795 // reallocate the old array or allocate a new one 8796 xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node))); 8797 assert(data); 8798 8799 // finalize 8800 _begin = data; 8801 _end = data + capacity; 8802 _eos = data + new_capacity; 8803 8804 // push 8805 *_end++ = node; 8806 } 8807 PUGI__NS_END 8808 8809 PUGI__NS_BEGIN 6298 8810 struct xpath_context 6299 8811 { … … 6301 8813 size_t position, size; 6302 8814 6303 xpath_context(const xpath_node& n , size_t position, size_t size): n(n), position(position), size(size)8815 xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_) 6304 8816 { 6305 8817 } … … 6367 8879 next(); 6368 8880 } 6369 8881 6370 8882 const char_t* state() const 6371 8883 { 6372 8884 return _cur; 6373 8885 } 6374 8886 6375 8887 void next() 6376 8888 { 6377 8889 const char_t* cur = _cur; 6378 8890 6379 while ( IS_CHARTYPE(*cur, ct_space)) ++cur;8891 while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur; 6380 8892 6381 8893 // save lexeme position for error reporting … … 6387 8899 _cur_lexeme = lex_eof; 6388 8900 break; 6389 8901 6390 8902 case '>': 6391 8903 if (*(cur+1) == '=') … … 6431 8943 6432 8944 break; 6433 8945 6434 8946 case '+': 6435 8947 cur += 1; … … 6455 8967 6456 8968 break; 6457 8969 6458 8970 case '$': 6459 8971 cur += 1; 6460 8972 6461 if ( IS_CHARTYPEX(*cur, ctx_start_symbol))8973 if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) 6462 8974 { 6463 8975 _cur_lexeme_contents.begin = cur; 6464 8976 6465 while ( IS_CHARTYPEX(*cur, ctx_symbol)) cur++;6466 6467 if (cur[0] == ':' && IS_CHARTYPEX(cur[1], ctx_symbol)) // qname8977 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; 8978 8979 if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname 6468 8980 { 6469 8981 cur++; // : 6470 8982 6471 while ( IS_CHARTYPEX(*cur, ctx_symbol)) cur++;8983 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; 6472 8984 } 6473 8985 6474 8986 _cur_lexeme_contents.end = cur; 6475 8987 6476 8988 _cur_lexeme = lex_var_ref; 6477 8989 } … … 6494 9006 6495 9007 break; 6496 9008 6497 9009 case '[': 6498 9010 cur += 1; … … 6525 9037 } 6526 9038 break; 6527 9039 6528 9040 case '.': 6529 9041 if (*(cur+1) == '.') … … 6532 9044 _cur_lexeme = lex_double_dot; 6533 9045 } 6534 else if ( IS_CHARTYPEX(*(cur+1), ctx_digit))9046 else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit)) 6535 9047 { 6536 9048 _cur_lexeme_contents.begin = cur; // . … … 6538 9050 ++cur; 6539 9051 6540 while ( IS_CHARTYPEX(*cur, ctx_digit)) cur++;9052 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; 6541 9053 6542 9054 _cur_lexeme_contents.end = cur; 6543 9055 6544 9056 _cur_lexeme = lex_number; 6545 9057 } … … 6567 9079 while (*cur && *cur != terminator) cur++; 6568 9080 _cur_lexeme_contents.end = cur; 6569 9081 6570 9082 if (!*cur) 6571 9083 _cur_lexeme = lex_none; … … 6592 9104 6593 9105 default: 6594 if ( IS_CHARTYPEX(*cur, ctx_digit))9106 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) 6595 9107 { 6596 9108 _cur_lexeme_contents.begin = cur; 6597 9109 6598 while ( IS_CHARTYPEX(*cur, ctx_digit)) cur++;6599 9110 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; 9111 6600 9112 if (*cur == '.') 6601 9113 { 6602 9114 cur++; 6603 9115 6604 while ( IS_CHARTYPEX(*cur, ctx_digit)) cur++;9116 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; 6605 9117 } 6606 9118 … … 6609 9121 _cur_lexeme = lex_number; 6610 9122 } 6611 else if ( IS_CHARTYPEX(*cur, ctx_start_symbol))9123 else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) 6612 9124 { 6613 9125 _cur_lexeme_contents.begin = cur; 6614 9126 6615 while ( IS_CHARTYPEX(*cur, ctx_symbol)) cur++;9127 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; 6616 9128 6617 9129 if (cur[0] == ':') … … 6621 9133 cur += 2; // :* 6622 9134 } 6623 else if ( IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname9135 else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname 6624 9136 { 6625 9137 cur++; // : 6626 9138 6627 while ( IS_CHARTYPEX(*cur, ctx_symbol)) cur++;9139 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; 6628 9140 } 6629 9141 } 6630 9142 6631 9143 _cur_lexeme_contents.end = cur; 6632 9144 6633 9145 _cur_lexeme = lex_string; 6634 9146 } … … 6662 9174 enum ast_type_t 6663 9175 { 9176 ast_unknown, 6664 9177 ast_op_or, // left or right 6665 9178 ast_op_and, // left and right 6666 9179 ast_op_equal, // left = right 6667 ast_op_not_equal, 9180 ast_op_not_equal, // left != right 6668 9181 ast_op_less, // left < right 6669 9182 ast_op_greater, // left > right … … 6679 9192 ast_predicate, // apply predicate to set; next points to next predicate 6680 9193 ast_filter, // select * from left where right 6681 ast_filter_posinv, // select * from left where right; proximity position invariant6682 9194 ast_string_constant, // string constant 6683 9195 ast_number_constant, // number constant … … 6719 9231 ast_func_round, // round(left) 6720 9232 ast_step, // process set left with step 6721 ast_step_root // select root node 9233 ast_step_root, // select root node 9234 9235 ast_opt_translate_table, // translate(left, right, third) where right/third are constants 9236 ast_opt_compare_attribute // @name = 'string' 6722 9237 }; 6723 9238 … … 6738 9253 axis_self 6739 9254 }; 6740 9255 6741 9256 enum nodetest_t 6742 9257 { … … 6752 9267 }; 6753 9268 9269 enum predicate_t 9270 { 9271 predicate_default, 9272 predicate_posinv, 9273 predicate_constant, 9274 predicate_constant_one 9275 }; 9276 9277 enum nodeset_eval_t 9278 { 9279 nodeset_eval_all, 9280 nodeset_eval_any, 9281 nodeset_eval_first 9282 }; 9283 6754 9284 template <axis_t N> struct axis_to_type 6755 9285 { … … 6758 9288 6759 9289 template <axis_t N> const axis_t axis_to_type<N>::axis = N; 6760 9290 6761 9291 class xpath_ast_node 6762 9292 { … … 6766 9296 char _rettype; 6767 9297 6768 // for ast_step / ast_predicate9298 // for ast_step 6769 9299 char _axis; 9300 9301 // for ast_step/ast_predicate/ast_filter 6770 9302 char _test; 6771 9303 … … 6785 9317 // node test for ast_step (node name/namespace/node type/pi target) 6786 9318 const char_t* nodetest; 9319 // table for ast_opt_translate_table 9320 const unsigned char* table; 6787 9321 } _data; 6788 9322 … … 6814 9348 xpath_allocator_capture cr(stack.result); 6815 9349 6816 xpath_node_set_raw ls = lhs->eval_node_set(c, stack );6817 xpath_node_set_raw rs = rhs->eval_node_set(c, stack );9350 xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); 9351 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); 6818 9352 6819 9353 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) … … 6843 9377 6844 9378 double l = lhs->eval_number(c, stack); 6845 xpath_node_set_raw rs = rhs->eval_node_set(c, stack );9379 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); 6846 9380 6847 9381 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) … … 6860 9394 6861 9395 xpath_string l = lhs->eval_string(c, stack); 6862 xpath_node_set_raw rs = rhs->eval_node_set(c, stack );9396 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); 6863 9397 6864 9398 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) … … 6874 9408 } 6875 9409 6876 assert( !"Wrong types");9410 assert(false && "Wrong types"); 6877 9411 return false; 9412 } 9413 9414 static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval) 9415 { 9416 return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any; 6878 9417 } 6879 9418 … … 6888 9427 xpath_allocator_capture cr(stack.result); 6889 9428 6890 xpath_node_set_raw ls = lhs->eval_node_set(c, stack );6891 xpath_node_set_raw rs = rhs->eval_node_set(c, stack );9429 xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); 9430 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); 6892 9431 6893 9432 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li) … … 6913 9452 6914 9453 double l = lhs->eval_number(c, stack); 6915 xpath_node_set_raw rs = rhs->eval_node_set(c, stack );9454 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all); 6916 9455 6917 9456 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) … … 6929 9468 xpath_allocator_capture cr(stack.result); 6930 9469 6931 xpath_node_set_raw ls = lhs->eval_node_set(c, stack );9470 xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all); 6932 9471 double r = rhs->eval_number(c, stack); 6933 9472 … … 6944 9483 else 6945 9484 { 6946 assert( !"Wrong types");9485 assert(false && "Wrong types"); 6947 9486 return false; 6948 9487 } 6949 9488 } 6950 9489 6951 void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack)9490 static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) 6952 9491 { 6953 9492 assert(ns.size() >= first); 9493 assert(expr->rettype() != xpath_type_number); 6954 9494 6955 9495 size_t i = 1; 6956 9496 size_t size = ns.size() - first; 6957 9497 6958 9498 xpath_node* last = ns.begin() + first; 6959 9499 6960 9500 // remove_if... or well, sort of 6961 9501 for (xpath_node* it = last; it != ns.end(); ++it, ++i) 6962 9502 { 6963 9503 xpath_context c(*it, i, size); 6964 6965 if (expr->rettype() == xpath_type_number) 6966 { 6967 if (expr->eval_number(c, stack) == i) 6968 *last++ = *it; 6969 } 6970 else if (expr->eval_boolean(c, stack)) 9504 9505 if (expr->eval_boolean(c, stack)) 9506 { 6971 9507 *last++ = *it; 6972 } 6973 9508 9509 if (once) break; 9510 } 9511 } 9512 6974 9513 ns.truncate(last); 6975 9514 } 6976 9515 6977 void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack) 9516 static void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) 9517 { 9518 assert(ns.size() >= first); 9519 assert(expr->rettype() == xpath_type_number); 9520 9521 size_t i = 1; 9522 size_t size = ns.size() - first; 9523 9524 xpath_node* last = ns.begin() + first; 9525 9526 // remove_if... or well, sort of 9527 for (xpath_node* it = last; it != ns.end(); ++it, ++i) 9528 { 9529 xpath_context c(*it, i, size); 9530 9531 if (expr->eval_number(c, stack) == i) 9532 { 9533 *last++ = *it; 9534 9535 if (once) break; 9536 } 9537 } 9538 9539 ns.truncate(last); 9540 } 9541 9542 static void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) 9543 { 9544 assert(ns.size() >= first); 9545 assert(expr->rettype() == xpath_type_number); 9546 9547 size_t size = ns.size() - first; 9548 9549 xpath_node* last = ns.begin() + first; 9550 9551 xpath_context c(xpath_node(), 1, size); 9552 9553 double er = expr->eval_number(c, stack); 9554 9555 if (er >= 1.0 && er <= size) 9556 { 9557 size_t eri = static_cast<size_t>(er); 9558 9559 if (er == eri) 9560 { 9561 xpath_node r = last[eri - 1]; 9562 9563 *last++ = r; 9564 } 9565 } 9566 9567 ns.truncate(last); 9568 } 9569 9570 void apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once) 6978 9571 { 6979 9572 if (ns.size() == first) return; 6980 9573 9574 assert(_type == ast_filter || _type == ast_predicate); 9575 9576 if (_test == predicate_constant || _test == predicate_constant_one) 9577 apply_predicate_number_const(ns, first, _right, stack); 9578 else if (_right->rettype() == xpath_type_number) 9579 apply_predicate_number(ns, first, _right, stack, once); 9580 else 9581 apply_predicate_boolean(ns, first, _right, stack, once); 9582 } 9583 9584 void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval) 9585 { 9586 if (ns.size() == first) return; 9587 9588 bool last_once = eval_once(ns.type(), eval); 9589 6981 9590 for (xpath_ast_node* pred = _right; pred; pred = pred->_next) 6982 { 6983 apply_predicate(ns, first, pred->_left, stack); 6984 } 6985 } 6986 6987 void step_push(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& parent, xpath_allocator* alloc) 6988 { 6989 if (!a) return; 6990 6991 const char_t* name = a.name(); 6992 6993 // There are no attribute nodes corresponding to attributes that declare namespaces 6994 // That is, "xmlns:..." or "xmlns" 6995 if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')) return; 6996 9591 pred->apply_predicate(ns, first, stack, !pred->_next && last_once); 9592 } 9593 9594 bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc) 9595 { 9596 assert(a); 9597 9598 const char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT(""); 9599 6997 9600 switch (_test) 6998 9601 { 6999 9602 case nodetest_name: 7000 if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc); 9603 if (strequal(name, _data.nodetest) && is_xpath_attribute(name)) 9604 { 9605 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); 9606 return true; 9607 } 7001 9608 break; 7002 9609 7003 9610 case nodetest_type_node: 7004 9611 case nodetest_all: 7005 ns.push_back(xpath_node(a, parent), alloc); 9612 if (is_xpath_attribute(name)) 9613 { 9614 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); 9615 return true; 9616 } 7006 9617 break; 7007 9618 7008 9619 case nodetest_all_in_namespace: 7009 if (starts_with(name, _data.nodetest)) 7010 ns.push_back(xpath_node(a, parent), alloc); 9620 if (starts_with(name, _data.nodetest) && is_xpath_attribute(name)) 9621 { 9622 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); 9623 return true; 9624 } 7011 9625 break; 7012 9626 7013 9627 default: 7014 9628 ; 7015 9629 } 7016 } 7017 7018 void step_push(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc) 7019 { 7020 if (!n) return; 9630 9631 return false; 9632 } 9633 9634 bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc) 9635 { 9636 assert(n); 9637 9638 xml_node_type type = PUGI__NODETYPE(n); 7021 9639 7022 9640 switch (_test) 7023 9641 { 7024 9642 case nodetest_name: 7025 if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc); 9643 if (type == node_element && n->name && strequal(n->name, _data.nodetest)) 9644 { 9645 ns.push_back(xml_node(n), alloc); 9646 return true; 9647 } 7026 9648 break; 7027 9649 7028 9650 case nodetest_type_node: 7029 ns.push_back(n, alloc); 9651 ns.push_back(xml_node(n), alloc); 9652 return true; 9653 9654 case nodetest_type_comment: 9655 if (type == node_comment) 9656 { 9657 ns.push_back(xml_node(n), alloc); 9658 return true; 9659 } 7030 9660 break; 7031 7032 case nodetest_type_comment: 7033 if (n.type() == node_comment) 7034 ns.push_back(n, alloc); 9661 9662 case nodetest_type_text: 9663 if (type == node_pcdata || type == node_cdata) 9664 { 9665 ns.push_back(xml_node(n), alloc); 9666 return true; 9667 } 7035 9668 break; 7036 7037 case nodetest_type_text: 7038 if (n.type() == node_pcdata || n.type() == node_cdata) 7039 ns.push_back(n, alloc); 9669 9670 case nodetest_type_pi: 9671 if (type == node_pi) 9672 { 9673 ns.push_back(xml_node(n), alloc); 9674 return true; 9675 } 7040 9676 break; 7041 7042 case nodetest_type_pi: 7043 if (n.type() == node_pi) 7044 ns.push_back(n, alloc); 9677 9678 case nodetest_pi: 9679 if (type == node_pi && n->name && strequal(n->name, _data.nodetest)) 9680 { 9681 ns.push_back(xml_node(n), alloc); 9682 return true; 9683 } 7045 9684 break; 7046 7047 case nodetest_pi: 7048 if (n.type() == node_pi && strequal(n.name(), _data.nodetest)) 7049 ns.push_back(n, alloc); 9685 9686 case nodetest_all: 9687 if (type == node_element) 9688 { 9689 ns.push_back(xml_node(n), alloc); 9690 return true; 9691 } 7050 9692 break; 7051 7052 case nodetest_all: 7053 if (n.type() == node_element) 7054 ns.push_back(n, alloc); 9693 9694 case nodetest_all_in_namespace: 9695 if (type == node_element && n->name && starts_with(n->name, _data.nodetest)) 9696 { 9697 ns.push_back(xml_node(n), alloc); 9698 return true; 9699 } 7055 9700 break; 7056 7057 case nodetest_all_in_namespace: 7058 if (n.type() == node_element && starts_with(n.name(), _data.nodetest)) 7059 ns.push_back(n, alloc); 9701 9702 default: 9703 assert(false && "Unknown axis"); 9704 } 9705 9706 return false; 9707 } 9708 9709 template <class T> void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T) 9710 { 9711 const axis_t axis = T::axis; 9712 9713 switch (axis) 9714 { 9715 case axis_attribute: 9716 { 9717 for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute) 9718 if (step_push(ns, a, n, alloc) & once) 9719 return; 9720 7060 9721 break; 7061 7062 default: 7063 assert(!"Unknown axis"); 7064 } 7065 } 7066 7067 template <class T> void step_fill(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc, T) 7068 { 7069 const axis_t axis = T::axis; 7070 7071 switch (axis) 7072 { 7073 case axis_attribute: 7074 { 7075 for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute()) 7076 step_push(ns, a, n, alloc); 7077 9722 } 9723 9724 case axis_child: 9725 { 9726 for (xml_node_struct* c = n->first_child; c; c = c->next_sibling) 9727 if (step_push(ns, c, alloc) & once) 9728 return; 9729 7078 9730 break; 7079 9731 } 7080 7081 case axis_child: 7082 { 7083 for (xml_node c = n.first_child(); c; c = c.next_sibling()) 7084 step_push(ns, c, alloc); 7085 7086 break; 7087 } 7088 9732 7089 9733 case axis_descendant: 7090 9734 case axis_descendant_or_self: 7091 9735 { 7092 9736 if (axis == axis_descendant_or_self) 7093 step_push(ns, n, alloc);7094 7095 xml_node cur = n.first_child(); 7096 7097 while (cur && cur != n) 7098 {7099 step_push(ns, cur, alloc);7100 7101 if (cur.first_child())7102 cur = cur.first_child(); 7103 else if (cur.next_sibling())7104 cur = cur .next_sibling();9737 if (step_push(ns, n, alloc) & once) 9738 return; 9739 9740 xml_node_struct* cur = n->first_child; 9741 9742 while (cur) 9743 { 9744 if (step_push(ns, cur, alloc) & once) 9745 return; 9746 9747 if (cur->first_child) 9748 cur = cur->first_child; 7105 9749 else 7106 9750 { 7107 while (!cur.next_sibling() && cur != n) 7108 cur = cur.parent(); 7109 7110 if (cur != n) cur = cur.next_sibling(); 9751 while (!cur->next_sibling) 9752 { 9753 cur = cur->parent; 9754 9755 if (cur == n) return; 9756 } 9757 9758 cur = cur->next_sibling; 7111 9759 } 7112 9760 } 7113 9761 7114 9762 break; 7115 9763 } 7116 9764 7117 9765 case axis_following_sibling: 7118 9766 { 7119 for (xml_node c = n.next_sibling(); c; c = c.next_sibling()) 7120 step_push(ns, c, alloc); 7121 9767 for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling) 9768 if (step_push(ns, c, alloc) & once) 9769 return; 9770 7122 9771 break; 7123 9772 } 7124 9773 7125 9774 case axis_preceding_sibling: 7126 9775 { 7127 for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling()) 7128 step_push(ns, c, alloc); 7129 9776 for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c) 9777 if (step_push(ns, c, alloc) & once) 9778 return; 9779 7130 9780 break; 7131 9781 } 7132 9782 7133 9783 case axis_following: 7134 9784 { 7135 xml_node cur = n;9785 xml_node_struct* cur = n; 7136 9786 7137 9787 // exit from this node so that we don't include descendants 7138 while (cur && !cur.next_sibling()) cur = cur.parent(); 7139 cur = cur.next_sibling(); 7140 7141 for (;;) 7142 { 7143 step_push(ns, cur, alloc); 7144 7145 if (cur.first_child()) 7146 cur = cur.first_child(); 7147 else if (cur.next_sibling()) 7148 cur = cur.next_sibling(); 9788 while (!cur->next_sibling) 9789 { 9790 cur = cur->parent; 9791 9792 if (!cur) return; 9793 } 9794 9795 cur = cur->next_sibling; 9796 9797 while (cur) 9798 { 9799 if (step_push(ns, cur, alloc) & once) 9800 return; 9801 9802 if (cur->first_child) 9803 cur = cur->first_child; 7149 9804 else 7150 9805 { 7151 while (cur && !cur.next_sibling()) cur = cur.parent(); 7152 cur = cur.next_sibling(); 7153 7154 if (!cur) break; 9806 while (!cur->next_sibling) 9807 { 9808 cur = cur->parent; 9809 9810 if (!cur) return; 9811 } 9812 9813 cur = cur->next_sibling; 7155 9814 } 7156 9815 } … … 7161 9820 case axis_preceding: 7162 9821 { 7163 xml_node cur = n; 7164 7165 while (cur && !cur.previous_sibling()) cur = cur.parent(); 7166 cur = cur.previous_sibling(); 7167 7168 for (;;) 7169 { 7170 if (cur.last_child()) 7171 cur = cur.last_child(); 9822 xml_node_struct* cur = n; 9823 9824 // exit from this node so that we don't include descendants 9825 while (!cur->prev_sibling_c->next_sibling) 9826 { 9827 cur = cur->parent; 9828 9829 if (!cur) return; 9830 } 9831 9832 cur = cur->prev_sibling_c; 9833 9834 while (cur) 9835 { 9836 if (cur->first_child) 9837 cur = cur->first_child->prev_sibling_c; 7172 9838 else 7173 9839 { 7174 9840 // leaf node, can't be ancestor 7175 step_push(ns, cur, alloc); 7176 7177 if (cur.previous_sibling()) 7178 cur = cur.previous_sibling(); 7179 else 9841 if (step_push(ns, cur, alloc) & once) 9842 return; 9843 9844 while (!cur->prev_sibling_c->next_sibling) 7180 9845 { 7181 do 7182 { 7183 cur = cur.parent(); 7184 if (!cur) break; 7185 7186 if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc); 7187 } 7188 while (!cur.previous_sibling()); 7189 7190 cur = cur.previous_sibling(); 7191 7192 if (!cur) break; 9846 cur = cur->parent; 9847 9848 if (!cur) return; 9849 9850 if (!node_is_ancestor(cur, n)) 9851 if (step_push(ns, cur, alloc) & once) 9852 return; 7193 9853 } 9854 9855 cur = cur->prev_sibling_c; 7194 9856 } 7195 9857 } … … 7197 9859 break; 7198 9860 } 7199 9861 7200 9862 case axis_ancestor: 7201 9863 case axis_ancestor_or_self: 7202 9864 { 7203 9865 if (axis == axis_ancestor_or_self) 7204 step_push(ns, n, alloc); 7205 7206 xml_node cur = n.parent(); 7207 9866 if (step_push(ns, n, alloc) & once) 9867 return; 9868 9869 xml_node_struct* cur = n->parent; 9870 7208 9871 while (cur) 7209 9872 { 7210 step_push(ns, cur, alloc); 7211 7212 cur = cur.parent(); 7213 } 7214 9873 if (step_push(ns, cur, alloc) & once) 9874 return; 9875 9876 cur = cur->parent; 9877 } 9878 7215 9879 break; 7216 9880 } … … 7225 9889 case axis_parent: 7226 9890 { 7227 if (n.parent()) step_push(ns, n.parent(), alloc); 9891 if (n->parent) 9892 step_push(ns, n->parent, alloc); 7228 9893 7229 9894 break; 7230 9895 } 7231 9896 7232 9897 default: 7233 assert( !"Unimplemented axis");7234 } 7235 } 7236 7237 template <class T> void step_fill(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& p, xpath_allocator* alloc, T v)9898 assert(false && "Unimplemented axis"); 9899 } 9900 } 9901 9902 template <class T> void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v) 7238 9903 { 7239 9904 const axis_t axis = T::axis; … … 7245 9910 { 7246 9911 if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test 7247 step_push(ns, a, p, alloc); 7248 7249 xml_node cur = p; 7250 9912 if (step_push(ns, a, p, alloc) & once) 9913 return; 9914 9915 xml_node_struct* cur = p; 9916 7251 9917 while (cur) 7252 9918 { 7253 step_push(ns, cur, alloc); 7254 7255 cur = cur.parent(); 7256 } 7257 9919 if (step_push(ns, cur, alloc) & once) 9920 return; 9921 9922 cur = cur->parent; 9923 } 9924 7258 9925 break; 7259 9926 } … … 7270 9937 case axis_following: 7271 9938 { 7272 xml_node cur = p; 7273 7274 for (;;) 7275 { 7276 if (cur.first_child()) 7277 cur = cur.first_child(); 7278 else if (cur.next_sibling()) 7279 cur = cur.next_sibling(); 9939 xml_node_struct* cur = p; 9940 9941 while (cur) 9942 { 9943 if (cur->first_child) 9944 cur = cur->first_child; 7280 9945 else 7281 9946 { 7282 while (cur && !cur.next_sibling()) cur = cur.parent(); 7283 cur = cur.next_sibling(); 7284 7285 if (!cur) break; 9947 while (!cur->next_sibling) 9948 { 9949 cur = cur->parent; 9950 9951 if (!cur) return; 9952 } 9953 9954 cur = cur->next_sibling; 7286 9955 } 7287 9956 7288 step_push(ns, cur, alloc); 9957 if (step_push(ns, cur, alloc) & once) 9958 return; 7289 9959 } 7290 9960 … … 7302 9972 { 7303 9973 // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding 7304 step_fill(ns, p, alloc, v);9974 step_fill(ns, p, alloc, once, v); 7305 9975 break; 7306 9976 } 7307 9977 7308 9978 default: 7309 assert( !"Unimplemented axis");7310 } 7311 } 7312 7313 template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, T v)9979 assert(false && "Unimplemented axis"); 9980 } 9981 } 9982 9983 template <class T> void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v) 7314 9984 { 7315 9985 const axis_t axis = T::axis; 7316 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); 9986 const bool axis_has_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); 9987 9988 if (xn.node()) 9989 step_fill(ns, xn.node().internal_object(), alloc, once, v); 9990 else if (axis_has_attributes && xn.attribute() && xn.parent()) 9991 step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v); 9992 } 9993 9994 template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v) 9995 { 9996 const axis_t axis = T::axis; 9997 const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling); 9998 const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; 9999 10000 bool once = 10001 (axis == axis_attribute && _test == nodetest_name) || 10002 (!_right && eval_once(axis_type, eval)) || 10003 (_right && !_right->_next && _right->_test == predicate_constant_one); 7317 10004 7318 10005 xpath_node_set_raw ns; 7319 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);10006 ns.set_type(axis_type); 7320 10007 7321 10008 if (_left) 7322 10009 { 7323 xpath_node_set_raw s = _left->eval_node_set(c, stack );10010 xpath_node_set_raw s = _left->eval_node_set(c, stack, nodeset_eval_all); 7324 10011 7325 10012 // self axis preserves the original order … … 7332 10019 // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes 7333 10020 if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); 7334 7335 if (it->node()) 7336 step_fill(ns, it->node(), stack.result, v); 7337 else if (attributes) 7338 step_fill(ns, it->attribute(), it->parent(), stack.result, v); 7339 7340 apply_predicates(ns, size, stack); 10021 10022 step_fill(ns, *it, stack.result, once, v); 10023 if (_right) apply_predicates(ns, size, stack, eval); 7341 10024 } 7342 10025 } 7343 10026 else 7344 10027 { 7345 if (c.n.node()) 7346 step_fill(ns, c.n.node(), stack.result, v); 7347 else if (attributes) 7348 step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v); 7349 7350 apply_predicates(ns, 0, stack); 10028 step_fill(ns, c.n, stack.result, once, v); 10029 if (_right) apply_predicates(ns, 0, stack, eval); 7351 10030 } 7352 10031 … … 7358 10037 return ns; 7359 10038 } 7360 10039 7361 10040 public: 7362 xpath_ast_node(ast_type_t type, xpath_value_type rettype , const char_t* value):7363 _type( (char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0)10041 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): 10042 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) 7364 10043 { 7365 10044 assert(type == ast_string_constant); … … 7367 10046 } 7368 10047 7369 xpath_ast_node(ast_type_t type, xpath_value_type rettype , double value):7370 _type( (char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0)10048 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value): 10049 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) 7371 10050 { 7372 10051 assert(type == ast_number_constant); 7373 10052 _data.number = value; 7374 10053 } 7375 7376 xpath_ast_node(ast_type_t type, xpath_value_type rettype , xpath_variable* value):7377 _type( (char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0)10054 10055 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): 10056 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) 7378 10057 { 7379 10058 assert(type == ast_variable); 7380 10059 _data.variable = value; 7381 10060 } 7382 7383 xpath_ast_node(ast_type_t type, xpath_value_type rettype , xpath_ast_node* left = 0, xpath_ast_node* right = 0):7384 _type( (char)type), _rettype((char)rettype), _axis(0), _test(0), _left(left), _right(right), _next(0)10061 10062 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): 10063 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) 7385 10064 { 7386 10065 } 7387 10066 7388 10067 xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents): 7389 _type((char)type), _rettype(xpath_type_node_set), _axis((char)axis), _test((char)test), _left(left), _right(0), _next(0) 7390 { 10068 _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) 10069 { 10070 assert(type == ast_step); 7391 10071 _data.nodetest = contents; 10072 } 10073 10074 xpath_ast_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test): 10075 _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast<char>(test)), _left(left), _right(right), _next(0) 10076 { 10077 assert(type == ast_filter || type == ast_predicate); 7392 10078 } 7393 10079 … … 7408 10094 case ast_op_or: 7409 10095 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); 7410 10096 7411 10097 case ast_op_and: 7412 10098 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); 7413 10099 7414 10100 case ast_op_equal: 7415 10101 return compare_eq(_left, _right, c, stack, equal_to()); … … 7417 10103 case ast_op_not_equal: 7418 10104 return compare_eq(_left, _right, c, stack, not_equal_to()); 7419 10105 7420 10106 case ast_op_less: 7421 10107 return compare_rel(_left, _right, c, stack, less()); 7422 10108 7423 10109 case ast_op_greater: 7424 10110 return compare_rel(_right, _left, c, stack, less()); … … 7426 10112 case ast_op_less_or_equal: 7427 10113 return compare_rel(_left, _right, c, stack, less_equal()); 7428 10114 7429 10115 case ast_op_greater_or_equal: 7430 10116 return compare_rel(_right, _left, c, stack, less_equal()); … … 7452 10138 case ast_func_boolean: 7453 10139 return _left->eval_boolean(c, stack); 7454 10140 7455 10141 case ast_func_not: 7456 10142 return !_left->eval_boolean(c, stack); 7457 10143 7458 10144 case ast_func_true: 7459 10145 return true; 7460 10146 7461 10147 case ast_func_false: 7462 10148 return false; … … 7465 10151 { 7466 10152 if (c.n.attribute()) return false; 7467 10153 7468 10154 xpath_allocator_capture cr(stack.result); 7469 10155 7470 10156 xpath_string lang = _left->eval_string(c, stack); 7471 10157 7472 10158 for (xml_node n = c.n.node(); n; n = n.parent()) 7473 10159 { 7474 10160 xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); 7475 10161 7476 10162 if (a) 7477 10163 { 7478 10164 const char_t* value = a.value(); 7479 10165 7480 10166 // strnicmp / strncasecmp is not portable 7481 10167 for (const char_t* lit = lang.c_str(); *lit; ++lit) … … 7484 10170 ++value; 7485 10171 } 7486 10172 7487 10173 return *value == 0 || *value == '-'; 7488 10174 } 7489 10175 } 7490 10176 7491 10177 return false; 10178 } 10179 10180 case ast_opt_compare_attribute: 10181 { 10182 const char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string(); 10183 10184 xml_attribute attr = c.n.node().attribute(_left->_data.nodetest); 10185 10186 return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name()); 7492 10187 } 7493 10188 … … 7508 10203 case xpath_type_number: 7509 10204 return convert_number_to_boolean(eval_number(c, stack)); 7510 10205 7511 10206 case xpath_type_string: 7512 10207 { … … 7515 10210 return !eval_string(c, stack).empty(); 7516 10211 } 7517 7518 case xpath_type_node_set: 10212 10213 case xpath_type_node_set: 7519 10214 { 7520 10215 xpath_allocator_capture cr(stack.result); 7521 10216 7522 return !eval_node_set(c, stack ).empty();10217 return !eval_node_set(c, stack, nodeset_eval_any).empty(); 7523 10218 } 7524 10219 7525 10220 default: 7526 assert( !"Wrong expression for return type boolean");10221 assert(false && "Wrong expression for return type boolean"); 7527 10222 return false; 7528 10223 } … … 7537 10232 case ast_op_add: 7538 10233 return _left->eval_number(c, stack) + _right->eval_number(c, stack); 7539 10234 7540 10235 case ast_op_subtract: 7541 10236 return _left->eval_number(c, stack) - _right->eval_number(c, stack); … … 7557 10252 7558 10253 case ast_func_last: 7559 return (double)c.size;7560 10254 return static_cast<double>(c.size); 10255 7561 10256 case ast_func_position: 7562 return (double)c.position;10257 return static_cast<double>(c.position); 7563 10258 7564 10259 case ast_func_count: … … 7566 10261 xpath_allocator_capture cr(stack.result); 7567 10262 7568 return (double)_left->eval_node_set(c, stack).size();7569 } 7570 10263 return static_cast<double>(_left->eval_node_set(c, stack, nodeset_eval_all).size()); 10264 } 10265 7571 10266 case ast_func_string_length_0: 7572 10267 { 7573 10268 xpath_allocator_capture cr(stack.result); 7574 10269 7575 return (double)string_value(c.n, stack.result).length();7576 } 7577 10270 return static_cast<double>(string_value(c.n, stack.result).length()); 10271 } 10272 7578 10273 case ast_func_string_length_1: 7579 10274 { 7580 10275 xpath_allocator_capture cr(stack.result); 7581 10276 7582 return (double)_left->eval_string(c, stack).length();7583 } 7584 10277 return static_cast<double>(_left->eval_string(c, stack).length()); 10278 } 10279 7585 10280 case ast_func_number_0: 7586 10281 { … … 7589 10284 return convert_string_to_number(string_value(c.n, stack.result).c_str()); 7590 10285 } 7591 10286 7592 10287 case ast_func_number_1: 7593 10288 return _left->eval_number(c, stack); … … 7598 10293 7599 10294 double r = 0; 7600 7601 xpath_node_set_raw ns = _left->eval_node_set(c, stack );7602 10295 10296 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all); 10297 7603 10298 for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) 7604 10299 { … … 7607 10302 r += convert_string_to_number(string_value(*it, stack.result).c_str()); 7608 10303 } 7609 10304 7610 10305 return r; 7611 10306 } … … 7614 10309 { 7615 10310 double r = _left->eval_number(c, stack); 7616 10311 7617 10312 return r == r ? floor(r) : r; 7618 10313 } … … 7621 10316 { 7622 10317 double r = _left->eval_number(c, stack); 7623 10318 7624 10319 return r == r ? ceil(r) : r; 7625 10320 } … … 7627 10322 case ast_func_round: 7628 10323 return round_nearest_nzero(_left->eval_number(c, stack)); 7629 10324 7630 10325 case ast_variable: 7631 10326 { … … 7644 10339 case xpath_type_boolean: 7645 10340 return eval_boolean(c, stack) ? 1 : 0; 7646 10341 7647 10342 case xpath_type_string: 7648 10343 { … … 7651 10346 return convert_string_to_number(eval_string(c, stack).c_str()); 7652 10347 } 7653 10348 7654 10349 case xpath_type_node_set: 7655 10350 { … … 7658 10353 return convert_string_to_number(eval_string(c, stack).c_str()); 7659 10354 } 7660 10355 7661 10356 default: 7662 assert( !"Wrong expression for return type number");10357 assert(false && "Wrong expression for return type number"); 7663 10358 return 0; 7664 10359 } 7665 7666 } 7667 } 7668 } 7669 10360 10361 } 10362 } 10363 } 10364 7670 10365 xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) 7671 10366 { … … 7714 10409 *ri = 0; 7715 10410 7716 return xpath_string (result, true);10411 return xpath_string::from_heap_preallocated(result, ri); 7717 10412 } 7718 10413 … … 7722 10417 { 7723 10418 case ast_string_constant: 7724 return xpath_string _const(_data.string);7725 10419 return xpath_string::from_const(_data.string); 10420 7726 10421 case ast_func_local_name_0: 7727 10422 { 7728 10423 xpath_node na = c.n; 7729 7730 return xpath_string _const(local_name(na));10424 10425 return xpath_string::from_const(local_name(na)); 7731 10426 } 7732 10427 … … 7735 10430 xpath_allocator_capture cr(stack.result); 7736 10431 7737 xpath_node_set_raw ns = _left->eval_node_set(c, stack );10432 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); 7738 10433 xpath_node na = ns.first(); 7739 7740 return xpath_string _const(local_name(na));10434 10435 return xpath_string::from_const(local_name(na)); 7741 10436 } 7742 10437 … … 7744 10439 { 7745 10440 xpath_node na = c.n; 7746 7747 return xpath_string _const(qualified_name(na));10441 10442 return xpath_string::from_const(qualified_name(na)); 7748 10443 } 7749 10444 … … 7752 10447 xpath_allocator_capture cr(stack.result); 7753 10448 7754 xpath_node_set_raw ns = _left->eval_node_set(c, stack );10449 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); 7755 10450 xpath_node na = ns.first(); 7756 7757 return xpath_string _const(qualified_name(na));10451 10452 return xpath_string::from_const(qualified_name(na)); 7758 10453 } 7759 10454 … … 7761 10456 { 7762 10457 xpath_node na = c.n; 7763 7764 return xpath_string _const(namespace_uri(na));10458 10459 return xpath_string::from_const(namespace_uri(na)); 7765 10460 } 7766 10461 … … 7769 10464 xpath_allocator_capture cr(stack.result); 7770 10465 7771 xpath_node_set_raw ns = _left->eval_node_set(c, stack );10466 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); 7772 10467 xpath_node na = ns.first(); 7773 7774 return xpath_string _const(namespace_uri(na));10468 10469 return xpath_string::from_const(namespace_uri(na)); 7775 10470 } 7776 10471 … … 7794 10489 7795 10490 const char_t* pos = find_substring(s.c_str(), p.c_str()); 7796 7797 return pos ? xpath_string (s.c_str(), pos, stack.result) : xpath_string();7798 } 7799 10491 10492 return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string(); 10493 } 10494 7800 10495 case ast_func_substring_after: 7801 10496 { … … 7806 10501 xpath_string s = _left->eval_string(c, swapped_stack); 7807 10502 xpath_string p = _right->eval_string(c, swapped_stack); 7808 10503 7809 10504 const char_t* pos = find_substring(s.c_str(), p.c_str()); 7810 10505 if (!pos) return xpath_string(); 7811 10506 7812 const char_t* result = pos + p.length(); 7813 7814 return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result); 10507 const char_t* rbegin = pos + p.length(); 10508 const char_t* rend = s.c_str() + s.length(); 10509 10510 return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); 7815 10511 } 7816 10512 … … 7825 10521 7826 10522 double first = round_nearest(_right->eval_number(c, stack)); 7827 10523 7828 10524 if (is_nan(first)) return xpath_string(); // NaN 7829 10525 else if (first >= s_length + 1) return xpath_string(); 7830 7831 size_t pos = first < 1 ? 1 : (size_t)first;10526 10527 size_t pos = first < 1 ? 1 : static_cast<size_t>(first); 7832 10528 assert(1 <= pos && pos <= s_length + 1); 7833 10529 7834 10530 const char_t* rbegin = s.c_str() + (pos - 1); 7835 7836 return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin); 7837 } 7838 10531 const char_t* rend = s.c_str() + s.length(); 10532 10533 return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); 10534 } 10535 7839 10536 case ast_func_substring_3: 7840 10537 { … … 7848 10545 double first = round_nearest(_right->eval_number(c, stack)); 7849 10546 double last = first + round_nearest(_right->_next->eval_number(c, stack)); 7850 10547 7851 10548 if (is_nan(first) || is_nan(last)) return xpath_string(); 7852 10549 else if (first >= s_length + 1) return xpath_string(); 7853 10550 else if (first >= last) return xpath_string(); 7854 10551 else if (last < 1) return xpath_string(); 7855 7856 size_t pos = first < 1 ? 1 : (size_t)first;7857 size_t end = last >= s_length + 1 ? s_length + 1 : (size_t)last;10552 10553 size_t pos = first < 1 ? 1 : static_cast<size_t>(first); 10554 size_t end = last >= s_length + 1 ? s_length + 1 : static_cast<size_t>(last); 7858 10555 7859 10556 assert(1 <= pos && pos <= end && end <= s_length + 1); … … 7861 10558 const char_t* rend = s.c_str() + (end - 1); 7862 10559 7863 return (end == s_length + 1 && !s.uses_heap()) ? xpath_string _const(rbegin) : xpath_string(rbegin, rend, stack.result);10560 return (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result); 7864 10561 } 7865 10562 … … 7868 10565 xpath_string s = string_value(c.n, stack.result); 7869 10566 7870 normalize_space(s.data(stack.result)); 7871 7872 return s; 10567 char_t* begin = s.data(stack.result); 10568 char_t* end = normalize_space(begin); 10569 10570 return xpath_string::from_heap_preallocated(begin, end); 7873 10571 } 7874 10572 … … 7877 10575 xpath_string s = _left->eval_string(c, stack); 7878 10576 7879 normalize_space(s.data(stack.result)); 7880 7881 return s; 10577 char_t* begin = s.data(stack.result); 10578 char_t* end = normalize_space(begin); 10579 10580 return xpath_string::from_heap_preallocated(begin, end); 7882 10581 } 7883 10582 … … 7892 10591 xpath_string to = _right->_next->eval_string(c, swapped_stack); 7893 10592 7894 translate(s.data(stack.result), from.c_str(), to.c_str()); 7895 7896 return s; 10593 char_t* begin = s.data(stack.result); 10594 char_t* end = translate(begin, from.c_str(), to.c_str(), to.length()); 10595 10596 return xpath_string::from_heap_preallocated(begin, end); 10597 } 10598 10599 case ast_opt_translate_table: 10600 { 10601 xpath_string s = _left->eval_string(c, stack); 10602 10603 char_t* begin = s.data(stack.result); 10604 char_t* end = translate_table(begin, _data.table); 10605 10606 return xpath_string::from_heap_preallocated(begin, end); 7897 10607 } 7898 10608 … … 7902 10612 7903 10613 if (_rettype == xpath_type_string) 7904 return xpath_string _const(_data.variable->get_string());10614 return xpath_string::from_const(_data.variable->get_string()); 7905 10615 7906 10616 // fallthrough to type conversion … … 7912 10622 { 7913 10623 case xpath_type_boolean: 7914 return xpath_string _const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));7915 10624 return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); 10625 7916 10626 case xpath_type_number: 7917 10627 return convert_number_to_string(eval_number(c, stack), stack.result); 7918 10628 7919 10629 case xpath_type_node_set: 7920 10630 { … … 7923 10633 xpath_stack swapped_stack = {stack.temp, stack.result}; 7924 10634 7925 xpath_node_set_raw ns = eval_node_set(c, swapped_stack );10635 xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first); 7926 10636 return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); 7927 10637 } 7928 10638 7929 10639 default: 7930 assert( !"Wrong expression for return type string");10640 assert(false && "Wrong expression for return type string"); 7931 10641 return xpath_string(); 7932 10642 } … … 7935 10645 } 7936 10646 7937 xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack )10647 xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval) 7938 10648 { 7939 10649 switch (_type) … … 7945 10655 xpath_stack swapped_stack = {stack.temp, stack.result}; 7946 10656 7947 xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack );7948 xpath_node_set_raw rs = _right->eval_node_set(c, stack );7949 10657 xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack, eval); 10658 xpath_node_set_raw rs = _right->eval_node_set(c, stack, eval); 10659 7950 10660 // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother 7951 10661 rs.set_type(xpath_node_set::type_unsorted); 7952 10662 7953 10663 rs.append(ls.begin(), ls.end(), stack.result); 7954 10664 rs.remove_duplicates(); 7955 10665 7956 10666 return rs; 7957 10667 } 7958 10668 7959 10669 case ast_filter: 7960 case ast_filter_posinv: 7961 { 7962 xpath_node_set_raw set = _left->eval_node_set(c, stack); 10670 { 10671 xpath_node_set_raw set = _left->eval_node_set(c, stack, _test == predicate_constant_one ? nodeset_eval_first : nodeset_eval_all); 7963 10672 7964 10673 // either expression is a number or it contains position() call; sort by document order 7965 if (_type == ast_filter) set.sort_do(); 7966 7967 apply_predicate(set, 0, _right, stack); 7968 10674 if (_test != predicate_posinv) set.sort_do(); 10675 10676 bool once = eval_once(set.type(), eval); 10677 10678 apply_predicate(set, 0, stack, once); 10679 7969 10680 return set; 7970 10681 } 7971 10682 7972 10683 case ast_func_id: 7973 10684 return xpath_node_set_raw(); 7974 10685 7975 10686 case ast_step: 7976 10687 { … … 7978 10689 { 7979 10690 case axis_ancestor: 7980 return step_do(c, stack, axis_to_type<axis_ancestor>());7981 10691 return step_do(c, stack, eval, axis_to_type<axis_ancestor>()); 10692 7982 10693 case axis_ancestor_or_self: 7983 return step_do(c, stack, axis_to_type<axis_ancestor_or_self>());10694 return step_do(c, stack, eval, axis_to_type<axis_ancestor_or_self>()); 7984 10695 7985 10696 case axis_attribute: 7986 return step_do(c, stack, axis_to_type<axis_attribute>());10697 return step_do(c, stack, eval, axis_to_type<axis_attribute>()); 7987 10698 7988 10699 case axis_child: 7989 return step_do(c, stack, axis_to_type<axis_child>());7990 10700 return step_do(c, stack, eval, axis_to_type<axis_child>()); 10701 7991 10702 case axis_descendant: 7992 return step_do(c, stack, axis_to_type<axis_descendant>());10703 return step_do(c, stack, eval, axis_to_type<axis_descendant>()); 7993 10704 7994 10705 case axis_descendant_or_self: 7995 return step_do(c, stack, axis_to_type<axis_descendant_or_self>());10706 return step_do(c, stack, eval, axis_to_type<axis_descendant_or_self>()); 7996 10707 7997 10708 case axis_following: 7998 return step_do(c, stack, axis_to_type<axis_following>());7999 10709 return step_do(c, stack, eval, axis_to_type<axis_following>()); 10710 8000 10711 case axis_following_sibling: 8001 return step_do(c, stack, axis_to_type<axis_following_sibling>());8002 10712 return step_do(c, stack, eval, axis_to_type<axis_following_sibling>()); 10713 8003 10714 case axis_namespace: 8004 10715 // namespaced axis is not supported 8005 10716 return xpath_node_set_raw(); 8006 10717 8007 10718 case axis_parent: 8008 return step_do(c, stack, axis_to_type<axis_parent>());8009 10719 return step_do(c, stack, eval, axis_to_type<axis_parent>()); 10720 8010 10721 case axis_preceding: 8011 return step_do(c, stack, axis_to_type<axis_preceding>());10722 return step_do(c, stack, eval, axis_to_type<axis_preceding>()); 8012 10723 8013 10724 case axis_preceding_sibling: 8014 return step_do(c, stack, axis_to_type<axis_preceding_sibling>());8015 10725 return step_do(c, stack, eval, axis_to_type<axis_preceding_sibling>()); 10726 8016 10727 case axis_self: 8017 return step_do(c, stack, axis_to_type<axis_self>()); 10728 return step_do(c, stack, eval, axis_to_type<axis_self>()); 10729 10730 default: 10731 assert(false && "Unknown axis"); 10732 return xpath_node_set_raw(); 8018 10733 } 8019 10734 } … … 8053 10768 8054 10769 default: 8055 assert( !"Wrong expression for return type node set");10770 assert(false && "Wrong expression for return type node set"); 8056 10771 return xpath_node_set_raw(); 8057 10772 } 8058 10773 } 8059 8060 bool is_posinv() 10774 10775 void optimize(xpath_allocator* alloc) 10776 { 10777 if (_left) 10778 _left->optimize(alloc); 10779 10780 if (_right) 10781 _right->optimize(alloc); 10782 10783 if (_next) 10784 _next->optimize(alloc); 10785 10786 optimize_self(alloc); 10787 } 10788 10789 void optimize_self(xpath_allocator* alloc) 10790 { 10791 // Rewrite [position()=expr] with [expr] 10792 // Note that this step has to go before classification to recognize [position()=1] 10793 if ((_type == ast_filter || _type == ast_predicate) && 10794 _right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number) 10795 { 10796 _right = _right->_right; 10797 } 10798 10799 // Classify filter/predicate ops to perform various optimizations during evaluation 10800 if (_type == ast_filter || _type == ast_predicate) 10801 { 10802 assert(_test == predicate_default); 10803 10804 if (_right->_type == ast_number_constant && _right->_data.number == 1.0) 10805 _test = predicate_constant_one; 10806 else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last)) 10807 _test = predicate_constant; 10808 else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr()) 10809 _test = predicate_posinv; 10810 } 10811 10812 // Rewrite descendant-or-self::node()/child::foo with descendant::foo 10813 // The former is a full form of //foo, the latter is much faster since it executes the node test immediately 10814 // Do a similar kind of rewrite for self/descendant/descendant-or-self axes 10815 // Note that we only rewrite positionally invariant steps (//foo[1] != /descendant::foo[1]) 10816 if (_type == ast_step && (_axis == axis_child || _axis == axis_self || _axis == axis_descendant || _axis == axis_descendant_or_self) && _left && 10817 _left->_type == ast_step && _left->_axis == axis_descendant_or_self && _left->_test == nodetest_type_node && !_left->_right && 10818 is_posinv_step()) 10819 { 10820 if (_axis == axis_child || _axis == axis_descendant) 10821 _axis = axis_descendant; 10822 else 10823 _axis = axis_descendant_or_self; 10824 10825 _left = _left->_left; 10826 } 10827 10828 // Use optimized lookup table implementation for translate() with constant arguments 10829 if (_type == ast_func_translate && _right->_type == ast_string_constant && _right->_next->_type == ast_string_constant) 10830 { 10831 unsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string); 10832 10833 if (table) 10834 { 10835 _type = ast_opt_translate_table; 10836 _data.table = table; 10837 } 10838 } 10839 10840 // Use optimized path for @attr = 'value' or @attr = $value 10841 if (_type == ast_op_equal && 10842 _left->_type == ast_step && _left->_axis == axis_attribute && _left->_test == nodetest_name && !_left->_left && !_left->_right && 10843 (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string))) 10844 { 10845 _type = ast_opt_compare_attribute; 10846 } 10847 } 10848 10849 bool is_posinv_expr() const 8061 10850 { 8062 10851 switch (_type) 8063 10852 { 8064 10853 case ast_func_position: 10854 case ast_func_last: 8065 10855 return false; 8066 10856 … … 8076 10866 case ast_predicate: 8077 10867 case ast_filter: 8078 case ast_filter_posinv:8079 10868 return true; 8080 10869 8081 10870 default: 8082 if (_left && !_left->is_posinv ()) return false;8083 10871 if (_left && !_left->is_posinv_expr()) return false; 10872 8084 10873 for (xpath_ast_node* n = _right; n; n = n->_next) 8085 if (!n->is_posinv ()) return false;8086 10874 if (!n->is_posinv_expr()) return false; 10875 8087 10876 return true; 8088 10877 } 8089 10878 } 8090 10879 10880 bool is_posinv_step() const 10881 { 10882 assert(_type == ast_step); 10883 10884 for (xpath_ast_node* n = _right; n; n = n->_next) 10885 { 10886 assert(n->_type == ast_predicate); 10887 10888 if (n->_test != predicate_posinv) 10889 return false; 10890 } 10891 10892 return true; 10893 } 10894 8091 10895 xpath_value_type rettype() const 8092 10896 { … … 8097 10901 struct xpath_parser 8098 10902 { 8099 8100 10903 xpath_allocator* _alloc; 10904 xpath_lexer _lexer; 8101 10905 8102 10906 const char_t* _query; … … 8104 10908 8105 10909 xpath_parse_result* _result; 10910 10911 char_t _scratch[32]; 8106 10912 8107 10913 #ifdef PUGIXML_NO_EXCEPTIONS … … 8122 10928 8123 10929 void throw_error_oom() 8124 8125 8126 8127 8128 8129 8130 10930 { 10931 #ifdef PUGIXML_NO_EXCEPTIONS 10932 throw_error("Out of memory"); 10933 #else 10934 throw std::bad_alloc(); 10935 #endif 10936 } 8131 10937 8132 10938 void* alloc_node() … … 8147 10953 char_t* c = static_cast<char_t*>(_alloc->allocate_nothrow((length + 1) * sizeof(char_t))); 8148 10954 if (!c) throw_error_oom(); 10955 assert(c); // workaround for clang static analysis 8149 10956 8150 10957 memcpy(c, value.begin, length * sizeof(char_t)); … … 8160 10967 assert(argc <= 1); 8161 10968 8162 if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); 10969 if (argc == 1 && args[0]->rettype() != xpath_type_node_set) 10970 throw_error("Function has to be applied to node set"); 8163 10971 8164 10972 return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); … … 8172 10980 if (name == PUGIXML_TEXT("boolean") && argc == 1) 8173 10981 return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); 8174 10982 8175 10983 break; 8176 10984 8177 10985 case 'c': 8178 10986 if (name == PUGIXML_TEXT("count") && argc == 1) 8179 10987 { 8180 if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); 10988 if (args[0]->rettype() != xpath_type_node_set) 10989 throw_error("Function has to be applied to node set"); 10990 8181 10991 return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); 8182 10992 } 8183 10993 else if (name == PUGIXML_TEXT("contains") && argc == 2) 8184 return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_ string, args[0], args[1]);10994 return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_boolean, args[0], args[1]); 8185 10995 else if (name == PUGIXML_TEXT("concat") && argc >= 2) 8186 10996 return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); 8187 10997 else if (name == PUGIXML_TEXT("ceiling") && argc == 1) 8188 10998 return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); 8189 10999 8190 11000 break; 8191 11001 8192 11002 case 'f': 8193 11003 if (name == PUGIXML_TEXT("false") && argc == 0) … … 8195 11005 else if (name == PUGIXML_TEXT("floor") && argc == 1) 8196 11006 return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); 8197 11007 8198 11008 break; 8199 11009 8200 11010 case 'i': 8201 11011 if (name == PUGIXML_TEXT("id") && argc == 1) 8202 11012 return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); 8203 11013 8204 11014 break; 8205 11015 8206 11016 case 'l': 8207 11017 if (name == PUGIXML_TEXT("last") && argc == 0) … … 8211 11021 else if (name == PUGIXML_TEXT("local-name") && argc <= 1) 8212 11022 return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); 8213 11023 8214 11024 break; 8215 11025 8216 11026 case 'n': 8217 11027 if (name == PUGIXML_TEXT("name") && argc <= 1) … … 8225 11035 else if (name == PUGIXML_TEXT("number") && argc <= 1) 8226 11036 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); 8227 11037 8228 11038 break; 8229 11039 8230 11040 case 'p': 8231 11041 if (name == PUGIXML_TEXT("position") && argc == 0) 8232 11042 return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); 8233 11043 8234 11044 break; 8235 11045 8236 11046 case 'r': 8237 11047 if (name == PUGIXML_TEXT("round") && argc == 1) … … 8239 11049 8240 11050 break; 8241 11051 8242 11052 case 's': 8243 11053 if (name == PUGIXML_TEXT("string") && argc <= 1) 8244 11054 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); 8245 11055 else if (name == PUGIXML_TEXT("string-length") && argc <= 1) 8246 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_ string, args[0]);11056 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]); 8247 11057 else if (name == PUGIXML_TEXT("starts-with") && argc == 2) 8248 11058 return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]); … … 8260 11070 8261 11071 break; 8262 11072 8263 11073 case 't': 8264 11074 if (name == PUGIXML_TEXT("translate") && argc == 3) … … 8266 11076 else if (name == PUGIXML_TEXT("true") && argc == 0) 8267 11077 return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); 8268 11078 11079 break; 11080 11081 default: 8269 11082 break; 8270 11083 } … … 8288 11101 else if (name == PUGIXML_TEXT("attribute")) 8289 11102 return axis_attribute; 8290 11103 8291 11104 break; 8292 11105 8293 11106 case 'c': 8294 11107 if (name == PUGIXML_TEXT("child")) 8295 11108 return axis_child; 8296 11109 8297 11110 break; 8298 11111 8299 11112 case 'd': 8300 11113 if (name == PUGIXML_TEXT("descendant")) … … 8302 11115 else if (name == PUGIXML_TEXT("descendant-or-self")) 8303 11116 return axis_descendant_or_self; 8304 11117 8305 11118 break; 8306 11119 8307 11120 case 'f': 8308 11121 if (name == PUGIXML_TEXT("following")) … … 8310 11123 else if (name == PUGIXML_TEXT("following-sibling")) 8311 11124 return axis_following_sibling; 8312 11125 8313 11126 break; 8314 11127 8315 11128 case 'n': 8316 11129 if (name == PUGIXML_TEXT("namespace")) 8317 11130 return axis_namespace; 8318 11131 8319 11132 break; 8320 11133 8321 11134 case 'p': 8322 11135 if (name == PUGIXML_TEXT("parent")) … … 8326 11139 else if (name == PUGIXML_TEXT("preceding-sibling")) 8327 11140 return axis_preceding_sibling; 8328 11141 8329 11142 break; 8330 11143 8331 11144 case 's': 8332 11145 if (name == PUGIXML_TEXT("self")) 8333 11146 return axis_self; 8334 11147 11148 break; 11149 11150 default: 8335 11151 break; 8336 11152 } … … 8367 11183 8368 11184 break; 11185 11186 default: 11187 break; 8369 11188 } 8370 11189 … … 8372 11191 } 8373 11192 8374 8375 8376 8377 8378 8379 8380 11193 // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall 11194 xpath_ast_node* parse_primary_expression() 11195 { 11196 switch (_lexer.current()) 11197 { 11198 case lex_var_ref: 11199 { 8381 11200 xpath_lexer_string name = _lexer.contents(); 8382 11201 … … 8384 11203 throw_error("Unknown variable: variable set is not provided"); 8385 11204 8386 xpath_variable* var = get_variable(_variables, name.begin, name.end); 11205 xpath_variable* var = 0; 11206 if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var)) 11207 throw_error_oom(); 8387 11208 8388 11209 if (!var) … … 8391 11212 _lexer.next(); 8392 11213 8393 11214 return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var); 8394 11215 } 8395 11216 … … 8422 11243 double value = 0; 8423 11244 8424 if (!convert_string_to_number (_lexer.contents().begin, _lexer.contents().end, &value))11245 if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value)) 8425 11246 throw_error_oom(); 8426 11247 … … 8435 11256 xpath_ast_node* args[2] = {0}; 8436 11257 size_t argc = 0; 8437 11258 8438 11259 xpath_lexer_string function = _lexer.contents(); 8439 11260 _lexer.next(); 8440 11261 8441 11262 xpath_ast_node* last_arg = 0; 8442 11263 8443 11264 if (_lexer.current() != lex_open_brace) 8444 11265 throw_error("Unrecognized function call"); … … 8453 11274 throw_error("No comma between function arguments"); 8454 11275 _lexer.next(); 8455 11276 8456 11277 xpath_ast_node* n = parse_expression(); 8457 11278 8458 11279 if (argc < 2) args[argc] = n; 8459 11280 else last_arg->set_next(n); … … 8462 11283 last_arg = n; 8463 11284 } 8464 11285 8465 11286 _lexer.next(); 8466 11287 … … 8468 11289 } 8469 11290 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 11291 default: 11292 throw_error("Unrecognizable primary expression"); 11293 11294 return 0; 11295 } 11296 } 11297 11298 // FilterExpr ::= PrimaryExpr | FilterExpr Predicate 11299 // Predicate ::= '[' PredicateExpr ']' 11300 // PredicateExpr ::= Expr 11301 xpath_ast_node* parse_filter_expression() 11302 { 11303 xpath_ast_node* n = parse_primary_expression(); 11304 11305 while (_lexer.current() == lex_open_square_brace) 11306 { 11307 _lexer.next(); 8487 11308 8488 11309 xpath_ast_node* expr = parse_expression(); 8489 11310 8490 if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); 8491 8492 bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv(); 8493 8494 n = new (alloc_node()) xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr); 8495 8496 if (_lexer.current() != lex_close_square_brace) 8497 throw_error("Unmatched square brace"); 8498 8499 _lexer.next(); 8500 } 8501 8502 return n; 8503 } 8504 8505 // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep 8506 // AxisSpecifier ::= AxisName '::' | '@'? 8507 // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' 8508 // NameTest ::= '*' | NCName ':' '*' | QName 8509 // AbbreviatedStep ::= '.' | '..' 8510 xpath_ast_node* parse_step(xpath_ast_node* set) 8511 { 11311 if (n->rettype() != xpath_type_node_set) 11312 throw_error("Predicate has to be applied to node set"); 11313 11314 n = new (alloc_node()) xpath_ast_node(ast_filter, n, expr, predicate_default); 11315 11316 if (_lexer.current() != lex_close_square_brace) 11317 throw_error("Unmatched square brace"); 11318 11319 _lexer.next(); 11320 } 11321 11322 return n; 11323 } 11324 11325 // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep 11326 // AxisSpecifier ::= AxisName '::' | '@'? 11327 // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' 11328 // NameTest ::= '*' | NCName ':' '*' | QName 11329 // AbbreviatedStep ::= '.' | '..' 11330 xpath_ast_node* parse_step(xpath_ast_node* set) 11331 { 8512 11332 if (set && set->rettype() != xpath_type_node_set) 8513 11333 throw_error("Step has to be applied to node set"); … … 8520 11340 axis = axis_attribute; 8521 11341 axis_specified = true; 8522 11342 8523 11343 _lexer.next(); 8524 11344 } … … 8526 11346 { 8527 11347 _lexer.next(); 8528 11348 8529 11349 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); 8530 11350 } … … 8532 11352 { 8533 11353 _lexer.next(); 8534 11354 8535 11355 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); 8536 11356 } 8537 11357 8538 11358 nodetest_t nt_type = nodetest_none; 8539 11359 xpath_lexer_string nt_name; 8540 11360 8541 11361 if (_lexer.current() == lex_string) 8542 11362 { … … 8549 11369 { 8550 11370 // parse axis name 8551 if (axis_specified) throw_error("Two axis specifiers in one step"); 11371 if (axis_specified) 11372 throw_error("Two axis specifiers in one step"); 8552 11373 8553 11374 axis = parse_axis_name(nt_name, axis_specified); 8554 11375 8555 if (!axis_specified) throw_error("Unknown axis"); 11376 if (!axis_specified) 11377 throw_error("Unknown axis"); 8556 11378 8557 11379 // read actual node test … … 8571 11393 else throw_error("Unrecognized node test"); 8572 11394 } 8573 11395 8574 11396 if (nt_type == nodetest_none) 8575 11397 { … … 8578 11400 { 8579 11401 _lexer.next(); 8580 11402 8581 11403 if (_lexer.current() == lex_close_brace) 8582 11404 { … … 8585 11407 nt_type = parse_node_test_type(nt_name); 8586 11408 8587 if (nt_type == nodetest_none) throw_error("Unrecognized node type"); 8588 11409 if (nt_type == nodetest_none) 11410 throw_error("Unrecognized node type"); 11411 8589 11412 nt_name = xpath_lexer_string(); 8590 11413 } … … 8593 11416 if (_lexer.current() != lex_quoted_string) 8594 11417 throw_error("Only literals are allowed as arguments to processing-instruction()"); 8595 11418 8596 11419 nt_type = nodetest_pi; 8597 11420 nt_name = _lexer.contents(); 8598 11421 _lexer.next(); 8599 11422 8600 11423 if (_lexer.current() != lex_close_brace) 8601 11424 throw_error("Unmatched brace near processing-instruction()"); … … 8603 11426 } 8604 11427 else 11428 { 8605 11429 throw_error("Unmatched brace near node type test"); 8606 11430 } 8607 11431 } 8608 11432 // QName or NCName:* … … 8612 11436 { 8613 11437 nt_name.end--; // erase * 8614 11438 8615 11439 nt_type = nodetest_all_in_namespace; 8616 11440 } 8617 else nt_type = nodetest_name; 11441 else 11442 { 11443 nt_type = nodetest_name; 11444 } 8618 11445 } 8619 11446 } … … 8624 11451 _lexer.next(); 8625 11452 } 8626 else throw_error("Unrecognized node test"); 8627 8628 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); 8629 11453 else 11454 { 11455 throw_error("Unrecognized node test"); 11456 } 11457 11458 const char_t* nt_name_copy = alloc_string(nt_name); 11459 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, nt_name_copy); 11460 8630 11461 xpath_ast_node* last = 0; 8631 11462 8632 11463 while (_lexer.current() == lex_open_square_brace) 8633 11464 { 8634 11465 _lexer.next(); 8635 11466 8636 11467 xpath_ast_node* expr = parse_expression(); 8637 11468 8638 xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr);8639 11469 xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, 0, expr, predicate_default); 11470 8640 11471 if (_lexer.current() != lex_close_square_brace) 8641 11472 throw_error("Unmatched square brace"); 8642 11473 _lexer.next(); 8643 11474 8644 11475 if (last) last->set_next(pred); 8645 11476 else n->set_right(pred); 8646 11477 8647 11478 last = pred; 8648 11479 } 8649 11480 8650 11481 return n; 8651 8652 8653 8654 8655 11482 } 11483 11484 // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step 11485 xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) 11486 { 8656 11487 xpath_ast_node* n = parse_step(set); 8657 11488 8658 11489 while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) 8659 11490 { … … 8663 11494 if (l == lex_double_slash) 8664 11495 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); 8665 11496 8666 11497 n = parse_step(n); 8667 11498 } 8668 11499 8669 11500 return n; 8670 8671 8672 8673 8674 8675 11501 } 11502 11503 // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath 11504 // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath 11505 xpath_ast_node* parse_location_path() 11506 { 8676 11507 if (_lexer.current() == lex_slash) 8677 11508 { 8678 11509 _lexer.next(); 8679 11510 8680 11511 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); 8681 11512 … … 8691 11522 { 8692 11523 _lexer.next(); 8693 11524 8694 11525 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); 8695 11526 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); 8696 11527 8697 11528 return parse_relative_location_path(n); 8698 11529 } … … 8700 11531 // 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 8701 11532 return parse_relative_location_path(0); 8702 } 8703 8704 // PathExpr ::= LocationPath 8705 // | FilterExpr 8706 // | FilterExpr '/' RelativeLocationPath 8707 // | FilterExpr '//' RelativeLocationPath 8708 xpath_ast_node* parse_path_expression() 8709 { 11533 } 11534 11535 // PathExpr ::= LocationPath 11536 // | FilterExpr 11537 // | FilterExpr '/' RelativeLocationPath 11538 // | FilterExpr '//' RelativeLocationPath 11539 // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr 11540 // UnaryExpr ::= UnionExpr | '-' UnaryExpr 11541 xpath_ast_node* parse_path_or_unary_expression() 11542 { 8710 11543 // Clarification. 8711 11544 // PathExpr begins with either LocationPath or FilterExpr. … … 8715 11548 // function call. 8716 11549 8717 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || 11550 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || 8718 11551 _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || 8719 11552 _lexer.current() == lex_string) 8720 8721 8722 8723 8724 8725 8726 while ( IS_CHARTYPE(*state, ct_space)) ++state;8727 8728 11553 { 11554 if (_lexer.current() == lex_string) 11555 { 11556 // This is either a function call, or not - if not, we shall proceed with location path 11557 const char_t* state = _lexer.state(); 11558 11559 while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; 11560 11561 if (*state != '(') return parse_location_path(); 8729 11562 8730 11563 // This looks like a function call; however this still can be a node-test. Check it. 8731 if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); 8732 } 8733 8734 xpath_ast_node* n = parse_filter_expression(); 8735 8736 if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) 8737 { 11564 if (parse_node_test_type(_lexer.contents()) != nodetest_none) 11565 return parse_location_path(); 11566 } 11567 11568 xpath_ast_node* n = parse_filter_expression(); 11569 11570 if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) 11571 { 8738 11572 lexeme_t l = _lexer.current(); 8739 8740 11573 _lexer.next(); 11574 8741 11575 if (l == lex_double_slash) 8742 11576 { 8743 if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); 11577 if (n->rettype() != xpath_type_node_set) 11578 throw_error("Step has to be applied to node set"); 8744 11579 8745 11580 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); 8746 11581 } 8747 8748 // select from location path 8749 return parse_relative_location_path(n); 8750 } 8751 8752 return n; 8753 } 8754 else return parse_location_path(); 8755 } 8756 8757 // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr 8758 xpath_ast_node* parse_union_expression() 8759 { 8760 xpath_ast_node* n = parse_path_expression(); 8761 8762 while (_lexer.current() == lex_union) 8763 { 8764 _lexer.next(); 8765 8766 xpath_ast_node* expr = parse_union_expression(); 8767 8768 if (n->rettype() != xpath_type_node_set || expr->rettype() != xpath_type_node_set) 11582 11583 // select from location path 11584 return parse_relative_location_path(n); 11585 } 11586 11587 return n; 11588 } 11589 else if (_lexer.current() == lex_minus) 11590 { 11591 _lexer.next(); 11592 11593 // precedence 7+ - only parses union expressions 11594 xpath_ast_node* expr = parse_expression_rec(parse_path_or_unary_expression(), 7); 11595 11596 return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); 11597 } 11598 else 11599 { 11600 return parse_location_path(); 11601 } 11602 } 11603 11604 struct binary_op_t 11605 { 11606 ast_type_t asttype; 11607 xpath_value_type rettype; 11608 int precedence; 11609 11610 binary_op_t(): asttype(ast_unknown), rettype(xpath_type_none), precedence(0) 11611 { 11612 } 11613 11614 binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_) 11615 { 11616 } 11617 11618 static binary_op_t parse(xpath_lexer& lexer) 11619 { 11620 switch (lexer.current()) 11621 { 11622 case lex_string: 11623 if (lexer.contents() == PUGIXML_TEXT("or")) 11624 return binary_op_t(ast_op_or, xpath_type_boolean, 1); 11625 else if (lexer.contents() == PUGIXML_TEXT("and")) 11626 return binary_op_t(ast_op_and, xpath_type_boolean, 2); 11627 else if (lexer.contents() == PUGIXML_TEXT("div")) 11628 return binary_op_t(ast_op_divide, xpath_type_number, 6); 11629 else if (lexer.contents() == PUGIXML_TEXT("mod")) 11630 return binary_op_t(ast_op_mod, xpath_type_number, 6); 11631 else 11632 return binary_op_t(); 11633 11634 case lex_equal: 11635 return binary_op_t(ast_op_equal, xpath_type_boolean, 3); 11636 11637 case lex_not_equal: 11638 return binary_op_t(ast_op_not_equal, xpath_type_boolean, 3); 11639 11640 case lex_less: 11641 return binary_op_t(ast_op_less, xpath_type_boolean, 4); 11642 11643 case lex_greater: 11644 return binary_op_t(ast_op_greater, xpath_type_boolean, 4); 11645 11646 case lex_less_or_equal: 11647 return binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4); 11648 11649 case lex_greater_or_equal: 11650 return binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4); 11651 11652 case lex_plus: 11653 return binary_op_t(ast_op_add, xpath_type_number, 5); 11654 11655 case lex_minus: 11656 return binary_op_t(ast_op_subtract, xpath_type_number, 5); 11657 11658 case lex_multiply: 11659 return binary_op_t(ast_op_multiply, xpath_type_number, 6); 11660 11661 case lex_union: 11662 return binary_op_t(ast_op_union, xpath_type_node_set, 7); 11663 11664 default: 11665 return binary_op_t(); 11666 } 11667 } 11668 }; 11669 11670 xpath_ast_node* parse_expression_rec(xpath_ast_node* lhs, int limit) 11671 { 11672 binary_op_t op = binary_op_t::parse(_lexer); 11673 11674 while (op.asttype != ast_unknown && op.precedence >= limit) 11675 { 11676 _lexer.next(); 11677 11678 xpath_ast_node* rhs = parse_path_or_unary_expression(); 11679 11680 binary_op_t nextop = binary_op_t::parse(_lexer); 11681 11682 while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence) 11683 { 11684 rhs = parse_expression_rec(rhs, nextop.precedence); 11685 11686 nextop = binary_op_t::parse(_lexer); 11687 } 11688 11689 if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set)) 8769 11690 throw_error("Union operator has to be applied to node sets"); 8770 11691 8771 n = new (alloc_node()) xpath_ast_node(ast_op_union, xpath_type_node_set, n, expr); 8772 } 8773 8774 return n; 8775 } 8776 8777 // UnaryExpr ::= UnionExpr | '-' UnaryExpr 8778 xpath_ast_node* parse_unary_expression() 8779 { 8780 if (_lexer.current() == lex_minus) 8781 { 8782 _lexer.next(); 8783 8784 xpath_ast_node* expr = parse_unary_expression(); 8785 8786 return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); 8787 } 8788 else return parse_union_expression(); 8789 } 8790 8791 // MultiplicativeExpr ::= UnaryExpr 8792 // | MultiplicativeExpr '*' UnaryExpr 8793 // | MultiplicativeExpr 'div' UnaryExpr 8794 // | MultiplicativeExpr 'mod' UnaryExpr 8795 xpath_ast_node* parse_multiplicative_expression() 8796 { 8797 xpath_ast_node* n = parse_unary_expression(); 8798 8799 while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string && 8800 (_lexer.contents() == PUGIXML_TEXT("mod") || _lexer.contents() == PUGIXML_TEXT("div")))) 8801 { 8802 ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply : 8803 _lexer.contents().begin[0] == 'd' ? ast_op_divide : ast_op_mod; 8804 _lexer.next(); 8805 8806 xpath_ast_node* expr = parse_unary_expression(); 8807 8808 n = new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, expr); 8809 } 8810 8811 return n; 8812 } 8813 8814 // AdditiveExpr ::= MultiplicativeExpr 8815 // | AdditiveExpr '+' MultiplicativeExpr 8816 // | AdditiveExpr '-' MultiplicativeExpr 8817 xpath_ast_node* parse_additive_expression() 8818 { 8819 xpath_ast_node* n = parse_multiplicative_expression(); 8820 8821 while (_lexer.current() == lex_plus || _lexer.current() == lex_minus) 8822 { 8823 lexeme_t l = _lexer.current(); 8824 8825 _lexer.next(); 8826 8827 xpath_ast_node* expr = parse_multiplicative_expression(); 8828 8829 n = new (alloc_node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, xpath_type_number, n, expr); 8830 } 8831 8832 return n; 8833 } 8834 8835 // RelationalExpr ::= AdditiveExpr 8836 // | RelationalExpr '<' AdditiveExpr 8837 // | RelationalExpr '>' AdditiveExpr 8838 // | RelationalExpr '<=' AdditiveExpr 8839 // | RelationalExpr '>=' AdditiveExpr 8840 xpath_ast_node* parse_relational_expression() 8841 { 8842 xpath_ast_node* n = parse_additive_expression(); 8843 8844 while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal || 8845 _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal) 8846 { 8847 lexeme_t l = _lexer.current(); 8848 _lexer.next(); 8849 8850 xpath_ast_node* expr = parse_additive_expression(); 8851 8852 n = new (alloc_node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater : 8853 l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, xpath_type_boolean, n, expr); 8854 } 8855 8856 return n; 8857 } 8858 8859 // EqualityExpr ::= RelationalExpr 8860 // | EqualityExpr '=' RelationalExpr 8861 // | EqualityExpr '!=' RelationalExpr 8862 xpath_ast_node* parse_equality_expression() 8863 { 8864 xpath_ast_node* n = parse_relational_expression(); 8865 8866 while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal) 8867 { 8868 lexeme_t l = _lexer.current(); 8869 8870 _lexer.next(); 8871 8872 xpath_ast_node* expr = parse_relational_expression(); 8873 8874 n = new (alloc_node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, xpath_type_boolean, n, expr); 8875 } 8876 8877 return n; 8878 } 8879 8880 // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr 8881 xpath_ast_node* parse_and_expression() 8882 { 8883 xpath_ast_node* n = parse_equality_expression(); 8884 8885 while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("and")) 8886 { 8887 _lexer.next(); 8888 8889 xpath_ast_node* expr = parse_equality_expression(); 8890 8891 n = new (alloc_node()) xpath_ast_node(ast_op_and, xpath_type_boolean, n, expr); 8892 } 8893 8894 return n; 8895 } 8896 8897 // OrExpr ::= AndExpr | OrExpr 'or' AndExpr 8898 xpath_ast_node* parse_or_expression() 8899 { 8900 xpath_ast_node* n = parse_and_expression(); 8901 8902 while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("or")) 8903 { 8904 _lexer.next(); 8905 8906 xpath_ast_node* expr = parse_and_expression(); 8907 8908 n = new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, n, expr); 8909 } 8910 8911 return n; 8912 } 8913 11692 lhs = new (alloc_node()) xpath_ast_node(op.asttype, op.rettype, lhs, rhs); 11693 11694 op = binary_op_t::parse(_lexer); 11695 } 11696 11697 return lhs; 11698 } 11699 8914 11700 // Expr ::= OrExpr 11701 // OrExpr ::= AndExpr | OrExpr 'or' AndExpr 11702 // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr 11703 // EqualityExpr ::= RelationalExpr 11704 // | EqualityExpr '=' RelationalExpr 11705 // | EqualityExpr '!=' RelationalExpr 11706 // RelationalExpr ::= AdditiveExpr 11707 // | RelationalExpr '<' AdditiveExpr 11708 // | RelationalExpr '>' AdditiveExpr 11709 // | RelationalExpr '<=' AdditiveExpr 11710 // | RelationalExpr '>=' AdditiveExpr 11711 // AdditiveExpr ::= MultiplicativeExpr 11712 // | AdditiveExpr '+' MultiplicativeExpr 11713 // | AdditiveExpr '-' MultiplicativeExpr 11714 // MultiplicativeExpr ::= UnaryExpr 11715 // | MultiplicativeExpr '*' UnaryExpr 11716 // | MultiplicativeExpr 'div' UnaryExpr 11717 // | MultiplicativeExpr 'mod' UnaryExpr 8915 11718 xpath_ast_node* parse_expression() 8916 11719 { 8917 return parse_ or_expression();11720 return parse_expression_rec(parse_path_or_unary_expression(), 0); 8918 11721 } 8919 11722 … … 8925 11728 { 8926 11729 xpath_ast_node* result = parse_expression(); 8927 11730 11731 // check if there are unparsed tokens left 8928 11732 if (_lexer.current() != lex_eof) 8929 {8930 // there are still unparsed tokens left, error8931 11733 throw_error("Incorrect query"); 8932 } 8933 11734 8934 11735 return result; 8935 11736 } … … 8949 11750 }; 8950 11751 8951 8952 11752 struct xpath_query_impl 11753 { 8953 11754 static xpath_query_impl* create() 8954 11755 { 8955 void* memory = global_allocate(sizeof(xpath_query_impl)); 8956 8957 return new (memory) xpath_query_impl(); 8958 } 8959 8960 static void destroy(void* ptr) 8961 { 8962 if (!ptr) return; 8963 11756 void* memory = xml_memory::allocate(sizeof(xpath_query_impl)); 11757 if (!memory) return 0; 11758 11759 return new (memory) xpath_query_impl(); 11760 } 11761 11762 static void destroy(xpath_query_impl* impl) 11763 { 8964 11764 // free all allocated pages 8965 static_cast<xpath_query_impl*>(ptr)->alloc.release();11765 impl->alloc.release(); 8966 11766 8967 11767 // free allocator memory (with the first page) 8968 global_deallocate(ptr); 8969 } 8970 8971 xpath_query_impl(): root(0), alloc(&block) 8972 { 8973 block.next = 0; 8974 } 8975 8976 xpath_ast_node* root; 8977 xpath_allocator alloc; 8978 xpath_memory_block block; 8979 }; 8980 8981 xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd) 11768 xml_memory::deallocate(impl); 11769 } 11770 11771 xpath_query_impl(): root(0), alloc(&block) 11772 { 11773 block.next = 0; 11774 block.capacity = sizeof(block.data); 11775 } 11776 11777 xpath_ast_node* root; 11778 xpath_allocator alloc; 11779 xpath_memory_block block; 11780 }; 11781 11782 PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd) 8982 11783 { 8983 11784 if (!impl) return xpath_string(); … … 8991 11792 return impl->root->eval_string(c, sd.stack); 8992 11793 } 8993 } 11794 11795 PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl) 11796 { 11797 if (!impl) return 0; 11798 11799 if (impl->root->rettype() != xpath_type_node_set) 11800 { 11801 #ifdef PUGIXML_NO_EXCEPTIONS 11802 return 0; 11803 #else 11804 xpath_parse_result res; 11805 res.error = "Expression does not evaluate to node set"; 11806 11807 throw xpath_exception(res); 11808 #endif 11809 } 11810 11811 return impl->root; 11812 } 11813 PUGI__NS_END 8994 11814 8995 11815 namespace pugi 8996 11816 { 8997 11817 #ifndef PUGIXML_NO_EXCEPTIONS 8998 xpath_exception::xpath_exception(const xpath_parse_result& result): _result(result)8999 { 9000 assert( result.error);9001 } 9002 9003 const char* xpath_exception::what() const throw()11818 PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) 11819 { 11820 assert(_result.error); 11821 } 11822 11823 PUGI__FN const char* xpath_exception::what() const throw() 9004 11824 { 9005 11825 return _result.error; 9006 11826 } 9007 11827 9008 const xpath_parse_result& xpath_exception::result() const11828 PUGI__FN const xpath_parse_result& xpath_exception::result() const 9009 11829 { 9010 11830 return _result; 9011 11831 } 9012 11832 #endif 9013 9014 xpath_node::xpath_node()9015 { 9016 } 9017 9018 xpath_node::xpath_node(const xml_node& node): _node(node)9019 { 9020 } 9021 9022 xpath_node::xpath_node(const xml_attribute& attribute, const xml_node& parent): _node(attribute ? parent : xml_node()), _attribute(attribute)9023 { 9024 } 9025 9026 xml_node xpath_node::node() const11833 11834 PUGI__FN xpath_node::xpath_node() 11835 { 11836 } 11837 11838 PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) 11839 { 11840 } 11841 11842 PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) 11843 { 11844 } 11845 11846 PUGI__FN xml_node xpath_node::node() const 9027 11847 { 9028 11848 return _attribute ? xml_node() : _node; 9029 11849 } 9030 9031 xml_attribute xpath_node::attribute() const11850 11851 PUGI__FN xml_attribute xpath_node::attribute() const 9032 11852 { 9033 11853 return _attribute; 9034 11854 } 9035 9036 xml_node xpath_node::parent() const11855 11856 PUGI__FN xml_node xpath_node::parent() const 9037 11857 { 9038 11858 return _attribute ? _node : _node.parent(); 9039 11859 } 9040 11860 9041 xpath_node::operator xpath_node::unspecified_bool_type() const 9042 { 9043 return (_node || _attribute) ? &xpath_node::_node : 0; 9044 } 9045 9046 bool xpath_node::operator!() const 11861 PUGI__FN static void unspecified_bool_xpath_node(xpath_node***) 11862 { 11863 } 11864 11865 PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const 11866 { 11867 return (_node || _attribute) ? unspecified_bool_xpath_node : 0; 11868 } 11869 11870 PUGI__FN bool xpath_node::operator!() const 9047 11871 { 9048 11872 return !(_node || _attribute); 9049 11873 } 9050 11874 9051 bool xpath_node::operator==(const xpath_node& n) const11875 PUGI__FN bool xpath_node::operator==(const xpath_node& n) const 9052 11876 { 9053 11877 return _node == n._node && _attribute == n._attribute; 9054 11878 } 9055 9056 bool xpath_node::operator!=(const xpath_node& n) const11879 11880 PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const 9057 11881 { 9058 11882 return _node != n._node || _attribute != n._attribute; … … 9060 11884 9061 11885 #ifdef __BORLANDC__ 9062 bool operator&&(const xpath_node& lhs, bool rhs)11886 PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs) 9063 11887 { 9064 11888 return (bool)lhs && rhs; 9065 11889 } 9066 11890 9067 bool operator||(const xpath_node& lhs, bool rhs)11891 PUGI__FN bool operator||(const xpath_node& lhs, bool rhs) 9068 11892 { 9069 11893 return (bool)lhs || rhs; … … 9071 11895 #endif 9072 11896 9073 void xpath_node_set::_assign(const_iterator begin, const_iterator end)9074 { 9075 assert(begin <= end);9076 9077 size_t size = static_cast<size_t>(end - begin);9078 9079 if (size <= 1)11897 PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_) 11898 { 11899 assert(begin_ <= end_); 11900 11901 size_t size_ = static_cast<size_t>(end_ - begin_); 11902 11903 if (size_ <= 1) 9080 11904 { 9081 11905 // deallocate old buffer 9082 if (_begin != &_storage) global_deallocate(_begin);11906 if (_begin != &_storage) impl::xml_memory::deallocate(_begin); 9083 11907 9084 11908 // use internal buffer 9085 if (begin != end) _storage = *begin;11909 if (begin_ != end_) _storage = *begin_; 9086 11910 9087 11911 _begin = &_storage; 9088 _end = &_storage + size; 11912 _end = &_storage + size_; 11913 _type = type_; 9089 11914 } 9090 11915 else 9091 11916 { 9092 11917 // make heap copy 9093 xpath_node* storage = static_cast<xpath_node*>( global_allocate(size* sizeof(xpath_node)));11918 xpath_node* storage = static_cast<xpath_node*>(impl::xml_memory::allocate(size_ * sizeof(xpath_node))); 9094 11919 9095 11920 if (!storage) … … 9102 11927 } 9103 11928 9104 memcpy(storage, begin , size* sizeof(xpath_node));9105 11929 memcpy(storage, begin_, size_ * sizeof(xpath_node)); 11930 9106 11931 // deallocate old buffer 9107 if (_begin != &_storage) global_deallocate(_begin);11932 if (_begin != &_storage) impl::xml_memory::deallocate(_begin); 9108 11933 9109 11934 // finalize 9110 11935 _begin = storage; 9111 _end = storage + size; 9112 } 9113 } 9114 9115 xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage) 9116 { 9117 } 9118 9119 xpath_node_set::xpath_node_set(const_iterator begin, const_iterator end, type_t type): _type(type), _begin(&_storage), _end(&_storage) 9120 { 9121 _assign(begin, end); 9122 } 9123 9124 xpath_node_set::~xpath_node_set() 9125 { 9126 if (_begin != &_storage) global_deallocate(_begin); 9127 } 9128 9129 xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage) 9130 { 9131 _assign(ns._begin, ns._end); 9132 } 9133 9134 xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) 11936 _end = storage + size_; 11937 _type = type_; 11938 } 11939 } 11940 11941 #ifdef PUGIXML_HAS_MOVE 11942 PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) 11943 { 11944 _type = rhs._type; 11945 _storage = rhs._storage; 11946 _begin = (rhs._begin == &rhs._storage) ? &_storage : rhs._begin; 11947 _end = _begin + (rhs._end - rhs._begin); 11948 11949 rhs._type = type_unsorted; 11950 rhs._begin = &rhs._storage; 11951 rhs._end = rhs._begin; 11952 } 11953 #endif 11954 11955 PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage) 11956 { 11957 } 11958 11959 PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(&_storage), _end(&_storage) 11960 { 11961 _assign(begin_, end_, type_); 11962 } 11963 11964 PUGI__FN xpath_node_set::~xpath_node_set() 11965 { 11966 if (_begin != &_storage) 11967 impl::xml_memory::deallocate(_begin); 11968 } 11969 11970 PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(&_storage), _end(&_storage) 11971 { 11972 _assign(ns._begin, ns._end, ns._type); 11973 } 11974 11975 PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) 9135 11976 { 9136 11977 if (this == &ns) return *this; 9137 9138 _type = ns._type; 9139 _assign(ns._begin, ns._end); 11978 11979 _assign(ns._begin, ns._end, ns._type); 9140 11980 9141 11981 return *this; 9142 11982 } 9143 11983 9144 xpath_node_set::type_t xpath_node_set::type() const 11984 #ifdef PUGIXML_HAS_MOVE 11985 PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs): _type(type_unsorted), _begin(&_storage), _end(&_storage) 11986 { 11987 _move(rhs); 11988 } 11989 11990 PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) 11991 { 11992 if (this == &rhs) return *this; 11993 11994 if (_begin != &_storage) 11995 impl::xml_memory::deallocate(_begin); 11996 11997 _move(rhs); 11998 11999 return *this; 12000 } 12001 #endif 12002 12003 PUGI__FN xpath_node_set::type_t xpath_node_set::type() const 9145 12004 { 9146 12005 return _type; 9147 12006 } 9148 9149 size_t xpath_node_set::size() const12007 12008 PUGI__FN size_t xpath_node_set::size() const 9150 12009 { 9151 12010 return _end - _begin; 9152 12011 } 9153 9154 bool xpath_node_set::empty() const12012 12013 PUGI__FN bool xpath_node_set::empty() const 9155 12014 { 9156 12015 return _begin == _end; 9157 12016 } 9158 9159 const xpath_node& xpath_node_set::operator[](size_t index) const12017 12018 PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const 9160 12019 { 9161 12020 assert(index < size()); … … 9163 12022 } 9164 12023 9165 xpath_node_set::const_iterator xpath_node_set::begin() const12024 PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const 9166 12025 { 9167 12026 return _begin; 9168 12027 } 9169 9170 xpath_node_set::const_iterator xpath_node_set::end() const12028 12029 PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const 9171 12030 { 9172 12031 return _end; 9173 12032 } 9174 9175 void xpath_node_set::sort(bool reverse) 9176 { 9177 _type = xpath_sort(_begin, _end, _type, reverse); 9178 } 9179 9180 xpath_node xpath_node_set::first() const 9181 { 9182 return xpath_first(_begin, _end, _type); 9183 } 9184 9185 xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) 9186 { 9187 } 9188 9189 xpath_parse_result::operator bool() const 9190 { 9191 return error == 0; 9192 } 9193 const char* xpath_parse_result::description() const 12033 12034 PUGI__FN void xpath_node_set::sort(bool reverse) 12035 { 12036 _type = impl::xpath_sort(_begin, _end, _type, reverse); 12037 } 12038 12039 PUGI__FN xpath_node xpath_node_set::first() const 12040 { 12041 return impl::xpath_first(_begin, _end, _type); 12042 } 12043 12044 PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0) 12045 { 12046 } 12047 12048 PUGI__FN xpath_parse_result::operator bool() const 12049 { 12050 return error == 0; 12051 } 12052 12053 PUGI__FN const char* xpath_parse_result::description() const 9194 12054 { 9195 12055 return error ? error : "No error"; 9196 12056 } 9197 12057 9198 xpath_variable::xpath_variable()9199 9200 9201 9202 const char_t* xpath_variable::name() const12058 PUGI__FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(0) 12059 { 12060 } 12061 12062 PUGI__FN const char_t* xpath_variable::name() const 9203 12063 { 9204 12064 switch (_type) 9205 12065 { 9206 12066 case xpath_type_node_set: 9207 return static_cast<const xpath_variable_node_set*>(this)->name;12067 return static_cast<const impl::xpath_variable_node_set*>(this)->name; 9208 12068 9209 12069 case xpath_type_number: 9210 return static_cast<const xpath_variable_number*>(this)->name;12070 return static_cast<const impl::xpath_variable_number*>(this)->name; 9211 12071 9212 12072 case xpath_type_string: 9213 return static_cast<const xpath_variable_string*>(this)->name;12073 return static_cast<const impl::xpath_variable_string*>(this)->name; 9214 12074 9215 12075 case xpath_type_boolean: 9216 return static_cast<const xpath_variable_boolean*>(this)->name;12076 return static_cast<const impl::xpath_variable_boolean*>(this)->name; 9217 12077 9218 12078 default: 9219 assert( !"Invalid variable type");12079 assert(false && "Invalid variable type"); 9220 12080 return 0; 9221 12081 } 9222 12082 } 9223 12083 9224 xpath_value_type xpath_variable::type() const12084 PUGI__FN xpath_value_type xpath_variable::type() const 9225 12085 { 9226 12086 return _type; 9227 12087 } 9228 12088 9229 bool xpath_variable::get_boolean() const9230 { 9231 return (_type == xpath_type_boolean) ? static_cast<const xpath_variable_boolean*>(this)->value : false;9232 } 9233 9234 double xpath_variable::get_number() const9235 { 9236 return (_type == xpath_type_number) ? static_cast<const xpath_variable_number*>(this)->value :gen_nan();9237 } 9238 9239 const char_t* xpath_variable::get_string() const9240 { 9241 const char_t* value = (_type == xpath_type_string) ? static_cast<const xpath_variable_string*>(this)->value : 0;12089 PUGI__FN bool xpath_variable::get_boolean() const 12090 { 12091 return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false; 12092 } 12093 12094 PUGI__FN double xpath_variable::get_number() const 12095 { 12096 return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number*>(this)->value : impl::gen_nan(); 12097 } 12098 12099 PUGI__FN const char_t* xpath_variable::get_string() const 12100 { 12101 const char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(this)->value : 0; 9242 12102 return value ? value : PUGIXML_TEXT(""); 9243 12103 } 9244 12104 9245 const xpath_node_set& xpath_variable::get_node_set() const9246 { 9247 return (_type == xpath_type_node_set) ? static_cast<const xpath_variable_node_set*>(this)->value :dummy_node_set;9248 } 9249 9250 bool xpath_variable::set(bool value)12105 PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const 12106 { 12107 return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set; 12108 } 12109 12110 PUGI__FN bool xpath_variable::set(bool value) 9251 12111 { 9252 12112 if (_type != xpath_type_boolean) return false; 9253 12113 9254 static_cast< xpath_variable_boolean*>(this)->value = value;12114 static_cast<impl::xpath_variable_boolean*>(this)->value = value; 9255 12115 return true; 9256 12116 } 9257 12117 9258 bool xpath_variable::set(double value)12118 PUGI__FN bool xpath_variable::set(double value) 9259 12119 { 9260 12120 if (_type != xpath_type_number) return false; 9261 12121 9262 static_cast< xpath_variable_number*>(this)->value = value;12122 static_cast<impl::xpath_variable_number*>(this)->value = value; 9263 12123 return true; 9264 12124 } 9265 12125 9266 bool xpath_variable::set(const char_t* value)12126 PUGI__FN bool xpath_variable::set(const char_t* value) 9267 12127 { 9268 12128 if (_type != xpath_type_string) return false; 9269 12129 9270 xpath_variable_string* var = static_cast<xpath_variable_string*>(this);12130 impl::xpath_variable_string* var = static_cast<impl::xpath_variable_string*>(this); 9271 12131 9272 12132 // duplicate string 9273 size_t size = ( strlength(value) + 1) * sizeof(char_t);9274 9275 char_t* copy = static_cast<char_t*>( global_allocate(size));12133 size_t size = (impl::strlength(value) + 1) * sizeof(char_t); 12134 12135 char_t* copy = static_cast<char_t*>(impl::xml_memory::allocate(size)); 9276 12136 if (!copy) return false; 9277 12137 … … 9279 12139 9280 12140 // replace old string 9281 if (var->value) global_deallocate(var->value);12141 if (var->value) impl::xml_memory::deallocate(var->value); 9282 12142 var->value = copy; 9283 12143 … … 9285 12145 } 9286 12146 9287 bool xpath_variable::set(const xpath_node_set& value)12147 PUGI__FN bool xpath_variable::set(const xpath_node_set& value) 9288 12148 { 9289 12149 if (_type != xpath_type_node_set) return false; 9290 12150 9291 static_cast< xpath_variable_node_set*>(this)->value = value;12151 static_cast<impl::xpath_variable_node_set*>(this)->value = value; 9292 12152 return true; 9293 12153 } 9294 12154 9295 xpath_variable_set::xpath_variable_set() 9296 { 9297 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0; 9298 } 9299 9300 xpath_variable_set::~xpath_variable_set() 12155 PUGI__FN xpath_variable_set::xpath_variable_set() 9301 12156 { 9302 12157 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) 9303 { 9304 xpath_variable* var = _data[i]; 9305 9306 while (var) 9307 { 9308 xpath_variable* next = var->_next; 9309 9310 delete_xpath_variable(var->_type, var); 9311 9312 var = next; 9313 } 9314 } 9315 } 9316 9317 xpath_variable* xpath_variable_set::find(const char_t* name) const 12158 _data[i] = 0; 12159 } 12160 12161 PUGI__FN xpath_variable_set::~xpath_variable_set() 12162 { 12163 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) 12164 _destroy(_data[i]); 12165 } 12166 12167 PUGI__FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs) 12168 { 12169 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) 12170 _data[i] = 0; 12171 12172 _assign(rhs); 12173 } 12174 12175 PUGI__FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs) 12176 { 12177 if (this == &rhs) return *this; 12178 12179 _assign(rhs); 12180 12181 return *this; 12182 } 12183 12184 #ifdef PUGIXML_HAS_MOVE 12185 PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) 12186 { 12187 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) 12188 { 12189 _data[i] = rhs._data[i]; 12190 rhs._data[i] = 0; 12191 } 12192 } 12193 12194 PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) 12195 { 12196 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) 12197 { 12198 _destroy(_data[i]); 12199 12200 _data[i] = rhs._data[i]; 12201 rhs._data[i] = 0; 12202 } 12203 12204 return *this; 12205 } 12206 #endif 12207 12208 PUGI__FN void xpath_variable_set::_assign(const xpath_variable_set& rhs) 12209 { 12210 xpath_variable_set temp; 12211 12212 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) 12213 if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i])) 12214 return; 12215 12216 _swap(temp); 12217 } 12218 12219 PUGI__FN void xpath_variable_set::_swap(xpath_variable_set& rhs) 12220 { 12221 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) 12222 { 12223 xpath_variable* chain = _data[i]; 12224 12225 _data[i] = rhs._data[i]; 12226 rhs._data[i] = chain; 12227 } 12228 } 12229 12230 PUGI__FN xpath_variable* xpath_variable_set::_find(const char_t* name) const 9318 12231 { 9319 12232 const size_t hash_size = sizeof(_data) / sizeof(_data[0]); 9320 size_t hash = hash_string(name) % hash_size;12233 size_t hash = impl::hash_string(name) % hash_size; 9321 12234 9322 12235 // look for existing variable 9323 12236 for (xpath_variable* var = _data[hash]; var; var = var->_next) 9324 if ( strequal(var->name(), name))12237 if (impl::strequal(var->name(), name)) 9325 12238 return var; 9326 12239 … … 9328 12241 } 9329 12242 9330 xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) 12243 PUGI__FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result) 12244 { 12245 xpath_variable* last = 0; 12246 12247 while (var) 12248 { 12249 // allocate storage for new variable 12250 xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name()); 12251 if (!nvar) return false; 12252 12253 // link the variable to the result immediately to handle failures gracefully 12254 if (last) 12255 last->_next = nvar; 12256 else 12257 *out_result = nvar; 12258 12259 last = nvar; 12260 12261 // copy the value; this can fail due to out-of-memory conditions 12262 if (!impl::copy_xpath_variable(nvar, var)) return false; 12263 12264 var = var->_next; 12265 } 12266 12267 return true; 12268 } 12269 12270 PUGI__FN void xpath_variable_set::_destroy(xpath_variable* var) 12271 { 12272 while (var) 12273 { 12274 xpath_variable* next = var->_next; 12275 12276 impl::delete_xpath_variable(var->_type, var); 12277 12278 var = next; 12279 } 12280 } 12281 12282 PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type) 9331 12283 { 9332 12284 const size_t hash_size = sizeof(_data) / sizeof(_data[0]); 9333 size_t hash = hash_string(name) % hash_size;12285 size_t hash = impl::hash_string(name) % hash_size; 9334 12286 9335 12287 // look for existing variable 9336 12288 for (xpath_variable* var = _data[hash]; var; var = var->_next) 9337 if ( strequal(var->name(), name))12289 if (impl::strequal(var->name(), name)) 9338 12290 return var->type() == type ? var : 0; 9339 12291 9340 12292 // add new variable 9341 xpath_variable* result = new_xpath_variable(type, name);12293 xpath_variable* result = impl::new_xpath_variable(type, name); 9342 12294 9343 12295 if (result) 9344 12296 { 9345 result->_type = type;9346 12297 result->_next = _data[hash]; 9347 12298 … … 9352 12303 } 9353 12304 9354 bool xpath_variable_set::set(const char_t* name, bool value)12305 PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value) 9355 12306 { 9356 12307 xpath_variable* var = add(name, xpath_type_boolean); … … 9358 12309 } 9359 12310 9360 bool xpath_variable_set::set(const char_t* name, double value)12311 PUGI__FN bool xpath_variable_set::set(const char_t* name, double value) 9361 12312 { 9362 12313 xpath_variable* var = add(name, xpath_type_number); … … 9364 12315 } 9365 12316 9366 bool xpath_variable_set::set(const char_t* name, const char_t* value)12317 PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value) 9367 12318 { 9368 12319 xpath_variable* var = add(name, xpath_type_string); … … 9370 12321 } 9371 12322 9372 bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)12323 PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value) 9373 12324 { 9374 12325 xpath_variable* var = add(name, xpath_type_node_set); … … 9376 12327 } 9377 12328 9378 xpath_variable* xpath_variable_set::get(const char_t* name)9379 { 9380 return find(name);9381 } 9382 9383 const xpath_variable* xpath_variable_set::get(const char_t* name) const9384 { 9385 return find(name);9386 } 9387 9388 xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)9389 { 9390 xpath_query_impl* impl =xpath_query_impl::create();9391 9392 if (! impl)12329 PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name) 12330 { 12331 return _find(name); 12332 } 12333 12334 PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const 12335 { 12336 return _find(name); 12337 } 12338 12339 PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0) 12340 { 12341 impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create(); 12342 12343 if (!qimpl) 9393 12344 { 9394 12345 #ifdef PUGIXML_NO_EXCEPTIONS 9395 12346 _result.error = "Out of memory"; 9396 12347 #else 9397 12348 throw std::bad_alloc(); 9398 12349 #endif … … 9400 12351 else 9401 12352 { 9402 buffer_holder impl_holder(impl, xpath_query_impl::destroy); 9403 9404 impl->root = xpath_parser::parse(query, variables, &impl->alloc, &_result); 9405 9406 if (impl->root) 9407 { 9408 _impl = static_cast<xpath_query_impl*>(impl_holder.release()); 12353 using impl::auto_deleter; // MSVC7 workaround 12354 auto_deleter<impl::xpath_query_impl> impl(qimpl, impl::xpath_query_impl::destroy); 12355 12356 qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result); 12357 12358 if (qimpl->root) 12359 { 12360 qimpl->root->optimize(&qimpl->alloc); 12361 12362 _impl = impl.release(); 9409 12363 _result.error = 0; 9410 12364 } … … 9412 12366 } 9413 12367 9414 xpath_query::~xpath_query() 9415 { 9416 xpath_query_impl::destroy(_impl); 9417 } 9418 9419 xpath_value_type xpath_query::return_type() const 12368 PUGI__FN xpath_query::xpath_query(): _impl(0) 12369 { 12370 } 12371 12372 PUGI__FN xpath_query::~xpath_query() 12373 { 12374 if (_impl) 12375 impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl)); 12376 } 12377 12378 #ifdef PUGIXML_HAS_MOVE 12379 PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) 12380 { 12381 _impl = rhs._impl; 12382 _result = rhs._result; 12383 rhs._impl = 0; 12384 rhs._result = xpath_parse_result(); 12385 } 12386 12387 PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs) 12388 { 12389 if (this == &rhs) return *this; 12390 12391 if (_impl) 12392 impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl)); 12393 12394 _impl = rhs._impl; 12395 _result = rhs._result; 12396 rhs._impl = 0; 12397 rhs._result = xpath_parse_result(); 12398 12399 return *this; 12400 } 12401 #endif 12402 12403 PUGI__FN xpath_value_type xpath_query::return_type() const 9420 12404 { 9421 12405 if (!_impl) return xpath_type_none; 9422 12406 9423 return static_cast< xpath_query_impl*>(_impl)->root->rettype();9424 } 9425 9426 bool xpath_query::evaluate_boolean(const xpath_node& n) const12407 return static_cast<impl::xpath_query_impl*>(_impl)->root->rettype(); 12408 } 12409 12410 PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const 9427 12411 { 9428 12412 if (!_impl) return false; 9429 9430 xpath_context c(n, 1, 1);9431 xpath_stack_data sd;12413 12414 impl::xpath_context c(n, 1, 1); 12415 impl::xpath_stack_data sd; 9432 12416 9433 12417 #ifdef PUGIXML_NO_EXCEPTIONS 9434 12418 if (setjmp(sd.error_handler)) return false; 9435 12419 #endif 9436 9437 return static_cast< xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);9438 } 9439 9440 double xpath_query::evaluate_number(const xpath_node& n) const9441 { 9442 if (!_impl) return gen_nan();9443 9444 xpath_context c(n, 1, 1);9445 xpath_stack_data sd;12420 12421 return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack); 12422 } 12423 12424 PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const 12425 { 12426 if (!_impl) return impl::gen_nan(); 12427 12428 impl::xpath_context c(n, 1, 1); 12429 impl::xpath_stack_data sd; 9446 12430 9447 12431 #ifdef PUGIXML_NO_EXCEPTIONS 9448 if (setjmp(sd.error_handler)) return gen_nan();12432 if (setjmp(sd.error_handler)) return impl::gen_nan(); 9449 12433 #endif 9450 12434 9451 return static_cast< xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);12435 return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack); 9452 12436 } 9453 12437 9454 12438 #ifndef PUGIXML_NO_STL 9455 string_t xpath_query::evaluate_string(const xpath_node& n) const 9456 { 9457 xpath_stack_data sd; 9458 9459 return evaluate_string_impl(static_cast<xpath_query_impl*>(_impl), n, sd).c_str(); 12439 PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const 12440 { 12441 impl::xpath_stack_data sd; 12442 12443 impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd); 12444 12445 return string_t(r.c_str(), r.length()); 9460 12446 } 9461 12447 #endif 9462 12448 9463 size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const9464 { 9465 xpath_stack_data sd;9466 9467 xpath_string r = evaluate_string_impl(static_cast<xpath_query_impl*>(_impl), n, sd);12449 PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const 12450 { 12451 impl::xpath_stack_data sd; 12452 12453 impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd); 9468 12454 9469 12455 size_t full_size = r.length() + 1; 9470 12456 9471 12457 if (capacity > 0) 9472 9473 9474 9475 9476 9477 9478 9479 12458 { 12459 size_t size = (full_size < capacity) ? full_size : capacity; 12460 assert(size > 0); 12461 12462 memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); 12463 buffer[size - 1] = 0; 12464 } 12465 9480 12466 return full_size; 9481 12467 } 9482 12468 9483 xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const 9484 { 9485 if (!_impl) return xpath_node_set(); 9486 9487 xpath_ast_node* root = static_cast<xpath_query_impl*>(_impl)->root; 9488 9489 if (root->rettype() != xpath_type_node_set) 9490 { 9491 #ifdef PUGIXML_NO_EXCEPTIONS 9492 return xpath_node_set(); 9493 #else 9494 xpath_parse_result result; 9495 result.error = "Expression does not evaluate to node set"; 9496 9497 throw xpath_exception(result); 9498 #endif 9499 } 9500 9501 xpath_context c(n, 1, 1); 9502 xpath_stack_data sd; 12469 PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const 12470 { 12471 impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl)); 12472 if (!root) return xpath_node_set(); 12473 12474 impl::xpath_context c(n, 1, 1); 12475 impl::xpath_stack_data sd; 9503 12476 9504 12477 #ifdef PUGIXML_NO_EXCEPTIONS … … 9506 12479 #endif 9507 12480 9508 xpath_node_set_raw r = root->eval_node_set(c, sd.stack);12481 impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all); 9509 12482 9510 12483 return xpath_node_set(r.begin(), r.end(), r.type()); 9511 12484 } 9512 12485 9513 const xpath_parse_result& xpath_query::result() const 12486 PUGI__FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const 12487 { 12488 impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl)); 12489 if (!root) return xpath_node(); 12490 12491 impl::xpath_context c(n, 1, 1); 12492 impl::xpath_stack_data sd; 12493 12494 #ifdef PUGIXML_NO_EXCEPTIONS 12495 if (setjmp(sd.error_handler)) return xpath_node(); 12496 #endif 12497 12498 impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first); 12499 12500 return r.first(); 12501 } 12502 12503 PUGI__FN const xpath_parse_result& xpath_query::result() const 9514 12504 { 9515 12505 return _result; 9516 12506 } 9517 12507 9518 xpath_query::operator xpath_query::unspecified_bool_type() const 9519 { 9520 return _impl ? &xpath_query::_impl : 0; 9521 } 9522 9523 bool xpath_query::operator!() const 12508 PUGI__FN static void unspecified_bool_xpath_query(xpath_query***) 12509 { 12510 } 12511 12512 PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const 12513 { 12514 return _impl ? unspecified_bool_xpath_query : 0; 12515 } 12516 12517 PUGI__FN bool xpath_query::operator!() const 9524 12518 { 9525 12519 return !_impl; 9526 12520 } 9527 12521 9528 xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const 12522 PUGI__FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const 12523 { 12524 xpath_query q(query, variables); 12525 return select_node(q); 12526 } 12527 12528 PUGI__FN xpath_node xml_node::select_node(const xpath_query& query) const 12529 { 12530 return query.evaluate_node(*this); 12531 } 12532 12533 PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const 12534 { 12535 xpath_query q(query, variables); 12536 return select_nodes(q); 12537 } 12538 12539 PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const 12540 { 12541 return query.evaluate_node_set(*this); 12542 } 12543 12544 PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const 9529 12545 { 9530 12546 xpath_query q(query, variables); … … 9532 12548 } 9533 12549 9534 xpath_node xml_node::select_single_node(const xpath_query& query) const 9535 { 9536 xpath_node_set s = query.evaluate_node_set(*this); 9537 return s.empty() ? xpath_node() : s.first(); 9538 } 9539 9540 xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const 9541 { 9542 xpath_query q(query, variables); 9543 return select_nodes(q); 9544 } 9545 9546 xpath_node_set xml_node::select_nodes(const xpath_query& query) const 9547 { 9548 return query.evaluate_node_set(*this); 12550 PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const 12551 { 12552 return query.evaluate_node(*this); 9549 12553 } 9550 12554 } … … 9552 12556 #endif 9553 12557 12558 #ifdef __BORLANDC__ 12559 # pragma option pop 12560 #endif 12561 12562 // Intel C++ does not properly keep warning state for function templates, 12563 // so popping warning state at the end of translation unit leads to warnings in the middle. 12564 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) 12565 # pragma warning(pop) 12566 #endif 12567 12568 // Undefine all local macros (makes sure we're not leaking macros in header-only mode) 12569 #undef PUGI__NO_INLINE 12570 #undef PUGI__UNLIKELY 12571 #undef PUGI__STATIC_ASSERT 12572 #undef PUGI__DMC_VOLATILE 12573 #undef PUGI__MSVC_CRT_VERSION 12574 #undef PUGI__NS_BEGIN 12575 #undef PUGI__NS_END 12576 #undef PUGI__FN 12577 #undef PUGI__FN_NO_INLINE 12578 #undef PUGI__GETHEADER_IMPL 12579 #undef PUGI__GETPAGE_IMPL 12580 #undef PUGI__GETPAGE 12581 #undef PUGI__NODETYPE 12582 #undef PUGI__IS_CHARTYPE_IMPL 12583 #undef PUGI__IS_CHARTYPE 12584 #undef PUGI__IS_CHARTYPEX 12585 #undef PUGI__ENDSWITH 12586 #undef PUGI__SKIPWS 12587 #undef PUGI__OPTSET 12588 #undef PUGI__PUSHNODE 12589 #undef PUGI__POPNODE 12590 #undef PUGI__SCANFOR 12591 #undef PUGI__SCANWHILE 12592 #undef PUGI__SCANWHILE_UNROLL 12593 #undef PUGI__ENDSEG 12594 #undef PUGI__THROW_ERROR 12595 #undef PUGI__CHECK_ERROR 12596 12597 #endif 12598 9554 12599 /** 9555 * Copyright (c) 2006-201 0Arseny Kapoulkine12600 * Copyright (c) 2006-2016 Arseny Kapoulkine 9556 12601 * 9557 12602 * Permission is hereby granted, free of charge, to any person … … 9566 12611 * The above copyright notice and this permission notice shall be 9567 12612 * included in all copies or substantial portions of the Software. 9568 * 12613 * 9569 12614 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 9570 12615 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
Note:
See TracChangeset
for help on using the changeset viewer.