Changeset 33a694 for ThirdParty
- 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)
- Location:
- ThirdParty/vmg/src/thirdparty/pugixml
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
ThirdParty/vmg/src/thirdparty/pugixml/pugiconfig.hpp
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 * … … 18 18 // #define PUGIXML_WCHAR_MODE 19 19 20 // Uncomment this to enable compact mode 21 // #define PUGIXML_COMPACT 22 20 23 // Uncomment this to disable XPath 21 24 // #define PUGIXML_NO_XPATH 22 25 23 26 // Uncomment this to disable STL 24 // Note: you can't use XPath with PUGIXML_NO_STL25 27 // #define PUGIXML_NO_STL 26 28 27 29 // Uncomment this to disable exceptions 28 // Note: you can't use XPath with PUGIXML_NO_EXCEPTIONS29 30 // #define PUGIXML_NO_EXCEPTIONS 30 31 … … 35 36 // In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead 36 37 38 // Tune these constants to adjust memory-related behavior 39 // #define PUGIXML_MEMORY_PAGE_SIZE 32768 40 // #define PUGIXML_MEMORY_OUTPUT_STACK 10240 41 // #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096 42 43 // Uncomment this to switch to header-only version 44 // #define PUGIXML_HEADER_ONLY 45 46 // Uncomment this to enable long long support 47 // #define PUGIXML_HAS_LONG_LONG 48 37 49 #endif 38 50 39 51 /** 40 * Copyright (c) 2006-201 0Arseny Kapoulkine52 * Copyright (c) 2006-2016 Arseny Kapoulkine 41 53 * 42 54 * Permission is hereby granted, free of charge, to any person … … 51 63 * The above copyright notice and this permission notice shall be 52 64 * included in all copies or substantial portions of the Software. 53 * 65 * 54 66 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 55 67 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -
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 -
ThirdParty/vmg/src/thirdparty/pugixml/pugixml.hpp
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 PUGIXML_VERSION 15 // Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons 16 # define PUGIXML_VERSION 180 17 #endif 18 19 // Include user configuration file (this can define various configuration macros) 20 #include "pugiconfig.hpp" 21 14 22 #ifndef HEADER_PUGIXML_HPP 15 23 #define HEADER_PUGIXML_HPP 16 24 17 #include "pugiconfig.hpp" 18 25 // Include stddef.h for size_t and ptrdiff_t 26 #include <stddef.h> 27 28 // Include exception header for XPath 29 #if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS) 30 # include <exception> 31 #endif 32 33 // Include STL headers 19 34 #ifndef PUGIXML_NO_STL 20 namespace std 21 { 22 struct bidirectional_iterator_tag; 23 24 #ifdef __SUNPRO_CC 25 // Sun C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions 26 template <class _T> class allocator; 27 template <class _charT> struct char_traits; 28 template <class _charT, class _Traits> class basic_istream; 29 template <class _charT, class _Traits> class basic_ostream; 30 template <class _charT, class _Traits, class _Allocator> class basic_string; 31 #else 32 // Borland C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions 33 template <class _Ty> class allocator; 34 template <class _Ty> struct char_traits; 35 template <class _Elem, class _Traits> class basic_istream; 36 template <class _Elem, class _Traits> class basic_ostream; 37 template <class _Elem, class _Traits, class _Ax> class basic_string; 38 #endif 39 40 // Digital Mars compiler has a bug which requires a forward declaration for explicit instantiation (otherwise type selection is messed up later, producing link errors) 41 // Also note that we have to declare char_traits as a class here, since it's defined that way 42 #ifdef __DMC__ 43 template <> class char_traits<char>; 44 #endif 45 } 35 # include <iterator> 36 # include <iosfwd> 37 # include <string> 46 38 #endif 47 39 … … 57 49 #endif 58 50 59 // Include exception header for XPath60 #if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS)61 # include <exception>62 #endif63 64 51 // If no API is defined, assume default 65 52 #ifndef PUGIXML_API 66 # 53 # define PUGIXML_API 67 54 #endif 68 55 69 56 // If no API for classes is defined, assume default 70 57 #ifndef PUGIXML_CLASS 71 # 58 # define PUGIXML_CLASS PUGIXML_API 72 59 #endif 73 60 74 61 // If no API for functions is defined, assume default 75 62 #ifndef PUGIXML_FUNCTION 76 # define PUGIXML_FUNCTION PUGIXML_API 77 #endif 78 79 #include <stddef.h> 63 # define PUGIXML_FUNCTION PUGIXML_API 64 #endif 65 66 // If the platform is known to have long long support, enable long long functions 67 #ifndef PUGIXML_HAS_LONG_LONG 68 # if __cplusplus >= 201103 69 # define PUGIXML_HAS_LONG_LONG 70 # elif defined(_MSC_VER) && _MSC_VER >= 1400 71 # define PUGIXML_HAS_LONG_LONG 72 # endif 73 #endif 74 75 // If the platform is known to have move semantics support, compile move ctor/operator implementation 76 #ifndef PUGIXML_HAS_MOVE 77 # if __cplusplus >= 201103 78 # define PUGIXML_HAS_MOVE 79 # elif defined(_MSC_VER) && _MSC_VER >= 1600 80 # define PUGIXML_HAS_MOVE 81 # endif 82 #endif 83 84 // If C++ is 2011 or higher, add 'override' qualifiers 85 #ifndef PUGIXML_OVERRIDE 86 # if __cplusplus >= 201103 87 # define PUGIXML_OVERRIDE override 88 # else 89 # define PUGIXML_OVERRIDE 90 # endif 91 #endif 80 92 81 93 // Character interface macros … … 105 117 enum xml_node_type 106 118 { 107 node_null, 119 node_null, // Empty (null) node handle 108 120 node_document, // A document tree's absolute root 109 121 node_element, // Element tag, i.e. '<node/>' … … 113 125 node_pi, // Processing instruction, i.e. '<?name?>' 114 126 node_declaration, // Document declaration, i.e. '<?xml version="1.0"?>' 115 node_doctype// Document type declaration, i.e. '<!DOCTYPE doc>'127 node_doctype // Document type declaration, i.e. '<!DOCTYPE doc>' 116 128 }; 117 129 … … 119 131 120 132 // Minimal parsing mode (equivalent to turning all other flags off). 121 133 // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed. 122 134 const unsigned int parse_minimal = 0x0000; 123 135 … … 132 144 133 145 // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree. 134 146 // This flag is off by default; turning it on usually results in slower parsing and more memory consumption. 135 147 const unsigned int parse_ws_pcdata = 0x0008; 136 148 … … 140 152 // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default. 141 153 const unsigned int parse_eol = 0x0020; 142 143 144 145 146 147 148 149 154 155 // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default. 156 const unsigned int parse_wconv_attribute = 0x0040; 157 158 // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default. 159 const unsigned int parse_wnorm_attribute = 0x0080; 160 161 // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default. 150 162 const unsigned int parse_declaration = 0x0100; 151 163 152 164 // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default. 153 165 const unsigned int parse_doctype = 0x0200; 154 166 167 // This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only 168 // of whitespace is added to the DOM tree. 169 // This flag is off by default; turning it on may result in slower parsing and more memory consumption. 170 const unsigned int parse_ws_pcdata_single = 0x0400; 171 172 // This flag determines if leading and trailing whitespace is to be removed from plain character data. This flag is off by default. 173 const unsigned int parse_trim_pcdata = 0x0800; 174 175 // This flag determines if plain character data that does not have a parent node is added to the DOM tree, and if an empty document 176 // is a valid document. This flag is off by default. 177 const unsigned int parse_fragment = 0x1000; 178 179 // This flag determines if plain character data is be stored in the parent element's value. This significantly changes the structure of 180 // the document; this flag is only recommended for parsing documents with many PCDATA nodes in memory-constrained environments. 181 // This flag is off by default. 182 const unsigned int parse_embed_pcdata = 0x2000; 183 155 184 // The default parsing mode. 156 157 185 // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded, 186 // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. 158 187 const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol; 159 188 160 161 162 163 189 // The full parsing mode. 190 // Nodes of all types are added to the DOM tree, character/reference entities are expanded, 191 // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules. 192 const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype; 164 193 165 194 // These flags determine the encoding of input data for XML document 166 195 enum xml_encoding 167 196 { 168 encoding_auto, // Auto-detect input encoding using BOM or < / <? detection; use UTF8 if BOM is not found 169 encoding_utf8, // UTF8 encoding 170 encoding_utf16_le, // Little-endian UTF16 171 encoding_utf16_be, // Big-endian UTF16 172 encoding_utf16, // UTF16 with native endianness 173 encoding_utf32_le, // Little-endian UTF32 174 encoding_utf32_be, // Big-endian UTF32 175 encoding_utf32, // UTF32 with native endianness 176 encoding_wchar // The same encoding wchar_t has (either UTF16 or UTF32) 197 encoding_auto, // Auto-detect input encoding using BOM or < / <? detection; use UTF8 if BOM is not found 198 encoding_utf8, // UTF8 encoding 199 encoding_utf16_le, // Little-endian UTF16 200 encoding_utf16_be, // Big-endian UTF16 201 encoding_utf16, // UTF16 with native endianness 202 encoding_utf32_le, // Little-endian UTF32 203 encoding_utf32_be, // Big-endian UTF32 204 encoding_utf32, // UTF32 with native endianness 205 encoding_wchar, // The same encoding wchar_t has (either UTF16 or UTF32) 206 encoding_latin1 177 207 }; 178 208 179 209 // Formatting flags 180 210 181 211 // Indent the nodes that are written to output stream with as many indentation strings as deep the node is in DOM tree. This flag is on by default. 182 212 const unsigned int format_indent = 0x01; 183 213 184 214 // Write encoding-specific BOM to the output stream. This flag is off by default. 185 215 const unsigned int format_write_bom = 0x02; … … 187 217 // Use raw output mode (no indentation and no line breaks are written). This flag is off by default. 188 218 const unsigned int format_raw = 0x04; 189 219 190 220 // Omit default XML declaration even if there is no declaration in the document. This flag is off by default. 191 221 const unsigned int format_no_declaration = 0x08; 192 222 223 // Don't escape attribute values and PCDATA contents. This flag is off by default. 224 const unsigned int format_no_escapes = 0x10; 225 226 // Open file using text mode in xml_document::save_file. This enables special character (i.e. new-line) conversions on some systems. This flag is off by default. 227 const unsigned int format_save_file_text = 0x20; 228 229 // Write every attribute on a new line with appropriate indentation. This flag is off by default. 230 const unsigned int format_indent_attributes = 0x40; 231 232 // Don't output empty element tags, instead writing an explicit start and end tag even if there are no children. This flag is off by default. 233 const unsigned int format_no_empty_element_tags = 0x80; 234 193 235 // The default set of formatting flags. 194 236 // Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none. 195 237 const unsigned int format_default = format_indent; 196 238 197 239 // Forward declarations 198 240 struct xml_attribute_struct; … … 201 243 class xml_node_iterator; 202 244 class xml_attribute_iterator; 245 class xml_named_node_iterator; 203 246 204 247 class xml_tree_walker; 205 248 249 struct xml_parse_result; 250 206 251 class xml_node; 252 253 class xml_text; 207 254 208 255 #ifndef PUGIXML_NO_XPATH … … 213 260 #endif 214 261 262 // Range-based for loop support 263 template <typename It> class xml_object_range 264 { 265 public: 266 typedef It const_iterator; 267 typedef It iterator; 268 269 xml_object_range(It b, It e): _begin(b), _end(e) 270 { 271 } 272 273 It begin() const { return _begin; } 274 It end() const { return _end; } 275 276 private: 277 It _begin, _end; 278 }; 279 215 280 // Writer interface for node printing (see xml_node::print) 216 281 class PUGIXML_CLASS xml_writer … … 227 292 { 228 293 public: 229 294 // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio 230 295 xml_writer_file(void* file); 231 296 232 virtual void write(const void* data, size_t size) ;297 virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; 233 298 234 299 private: … … 241 306 { 242 307 public: 243 308 // Construct writer from an output stream object 244 309 xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream); 245 310 xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream); 246 311 247 virtual void write(const void* data, size_t size) ;312 virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE; 248 313 249 314 private: … … 261 326 private: 262 327 xml_attribute_struct* _attr; 263 264 typedef xml_attribute_struct* xml_attribute::*unspecified_bool_type;265 266 public: 267 328 329 typedef void (*unspecified_bool_type)(xml_attribute***); 330 331 public: 332 // Default constructor. Constructs an empty attribute. 268 333 xml_attribute(); 269 270 334 335 // Constructs attribute from internal pointer 271 336 explicit xml_attribute(xml_attribute_struct* attr); 272 337 273 274 275 276 277 338 // Safe bool conversion operator 339 operator unspecified_bool_type() const; 340 341 // Borland C++ workaround 342 bool operator!() const; 278 343 279 344 // Comparison operators (compares wrapped attribute pointers) … … 292 357 const char_t* value() const; 293 358 294 // Get attribute value as a number, or 0 if conversion did not succeed or attribute is empty 295 int as_int() const; 296 unsigned int as_uint() const; 297 double as_double() const; 298 float as_float() const; 299 300 // Get attribute value as bool (returns true if first character is in '1tTyY' set), or false if attribute is empty 301 bool as_bool() const; 302 303 // Set attribute name/value (returns false if attribute is empty or there is not enough memory) 359 // Get attribute value, or the default value if attribute is empty 360 const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; 361 362 // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty 363 int as_int(int def = 0) const; 364 unsigned int as_uint(unsigned int def = 0) const; 365 double as_double(double def = 0) const; 366 float as_float(float def = 0) const; 367 368 #ifdef PUGIXML_HAS_LONG_LONG 369 long long as_llong(long long def = 0) const; 370 unsigned long long as_ullong(unsigned long long def = 0) const; 371 #endif 372 373 // Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty 374 bool as_bool(bool def = false) const; 375 376 // Set attribute name/value (returns false if attribute is empty or there is not enough memory) 304 377 bool set_name(const char_t* rhs); 305 378 bool set_value(const char_t* rhs); 306 379 307 380 // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") 308 381 bool set_value(int rhs); 309 382 bool set_value(unsigned int rhs); 383 bool set_value(long rhs); 384 bool set_value(unsigned long rhs); 310 385 bool set_value(double rhs); 386 bool set_value(float rhs); 311 387 bool set_value(bool rhs); 388 389 #ifdef PUGIXML_HAS_LONG_LONG 390 bool set_value(long long rhs); 391 bool set_value(unsigned long long rhs); 392 #endif 312 393 313 394 // Set attribute value (equivalent to set_value without error checking) … … 315 396 xml_attribute& operator=(int rhs); 316 397 xml_attribute& operator=(unsigned int rhs); 398 xml_attribute& operator=(long rhs); 399 xml_attribute& operator=(unsigned long rhs); 317 400 xml_attribute& operator=(double rhs); 401 xml_attribute& operator=(float rhs); 318 402 xml_attribute& operator=(bool rhs); 319 403 320 // Get next/previous attribute in the attribute list of the parent node 321 xml_attribute next_attribute() const; 322 xml_attribute previous_attribute() const; 323 324 // Get hash value (unique for handles to the same object) 325 size_t hash_value() const; 404 #ifdef PUGIXML_HAS_LONG_LONG 405 xml_attribute& operator=(long long rhs); 406 xml_attribute& operator=(unsigned long long rhs); 407 #endif 408 409 // Get next/previous attribute in the attribute list of the parent node 410 xml_attribute next_attribute() const; 411 xml_attribute previous_attribute() const; 412 413 // Get hash value (unique for handles to the same object) 414 size_t hash_value() const; 326 415 327 416 // Get internal pointer … … 340 429 friend class xml_attribute_iterator; 341 430 friend class xml_node_iterator; 431 friend class xml_named_node_iterator; 342 432 343 433 protected: 344 434 xml_node_struct* _root; 345 435 346 typedef xml_node_struct* xml_node::*unspecified_bool_type;436 typedef void (*unspecified_bool_type)(xml_node***); 347 437 348 438 public: … … 350 440 xml_node(); 351 441 352 442 // Constructs node from internal pointer 353 443 explicit xml_node(xml_node_struct* p); 354 444 355 445 // Safe bool conversion operator 356 446 operator unspecified_bool_type() const; 357 447 358 448 // Borland C++ workaround 359 449 bool operator!() const; 360 450 361 451 // Comparison operators (compares wrapped node pointers) 362 452 bool operator==(const xml_node& r) const; … … 373 463 xml_node_type type() const; 374 464 375 // Get node name /value, or "" if node is empty or it has no name/value465 // Get node name, or "" if node is empty or it has no name 376 466 const char_t* name() const; 467 468 // Get node value, or "" if node is empty or it has no value 469 // Note: For <node>text</node> node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes. 377 470 const char_t* value() const; 378 471 379 472 // Get attribute list 380 473 xml_attribute first_attribute() const; 381 382 383 474 xml_attribute last_attribute() const; 475 476 // Get children list 384 477 xml_node first_child() const; 385 386 387 478 xml_node last_child() const; 479 480 // Get next/previous sibling in the children list of the parent node 388 481 xml_node next_sibling() const; 389 482 xml_node previous_sibling() const; 390 391 483 484 // Get parent node 392 485 xml_node parent() const; 393 486 394 487 // Get root of DOM tree this node belongs to 395 488 xml_node root() const; 489 490 // Get text object for the current node 491 xml_text text() const; 396 492 397 493 // Get child, attribute or next/previous sibling with the specified name … … 401 497 xml_node previous_sibling(const char_t* name) const; 402 498 499 // Get attribute, starting the search from a hint (and updating hint so that searching for a sequence of attributes is fast) 500 xml_attribute attribute(const char_t* name, xml_attribute& hint) const; 501 403 502 // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA 404 503 const char_t* child_value() const; … … 410 509 bool set_name(const char_t* rhs); 411 510 bool set_value(const char_t* rhs); 412 511 413 512 // Add attribute with specified name. Returns added attribute, or empty attribute on errors. 414 513 xml_attribute append_attribute(const char_t* name); … … 441 540 xml_node insert_copy_before(const xml_node& proto, const xml_node& node); 442 541 542 // Move the specified node to become a child of this node. Returns moved node, or empty node on errors. 543 xml_node append_move(const xml_node& moved); 544 xml_node prepend_move(const xml_node& moved); 545 xml_node insert_move_after(const xml_node& moved, const xml_node& node); 546 xml_node insert_move_before(const xml_node& moved, const xml_node& node); 547 443 548 // Remove specified attribute 444 549 bool remove_attribute(const xml_attribute& a); … … 448 553 bool remove_child(const xml_node& n); 449 554 bool remove_child(const char_t* name); 555 556 // Parses buffer as an XML document fragment and appends all nodes as children of the current node. 557 // Copies/converts the buffer, so it may be deleted or changed after the function returns. 558 // Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory. 559 xml_parse_result append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); 450 560 451 561 // Find attribute using predicate. Returns first attribute for which predicate returned true. … … 453 563 { 454 564 if (!_root) return xml_attribute(); 455 565 456 566 for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute()) 457 567 if (pred(attrib)) 458 568 return attrib; 459 569 460 570 return xml_attribute(); 461 571 } … … 465 575 { 466 576 if (!_root) return xml_node(); 467 577 468 578 for (xml_node node = first_child(); node; node = node.next_sibling()) 469 579 if (pred(node)) 470 580 return node; 471 472 581 582 return xml_node(); 473 583 } 474 584 … … 479 589 480 590 xml_node cur = first_child(); 481 591 482 592 while (cur._root && cur._root != _root) 483 593 { … … 511 621 // Recursively traverse subtree with xml_tree_walker 512 622 bool traverse(xml_tree_walker& walker); 513 623 514 624 #ifndef PUGIXML_NO_XPATH 515 625 // Select single node by evaluating XPath query. Returns first node from the resulting node set. 516 xpath_node select_ single_node(const char_t* query, xpath_variable_set* variables = 0) const;517 xpath_node select_ single_node(const xpath_query& query) const;626 xpath_node select_node(const char_t* query, xpath_variable_set* variables = 0) const; 627 xpath_node select_node(const xpath_query& query) const; 518 628 519 629 // Select node set by evaluating XPath query 520 630 xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const; 521 631 xpath_node_set select_nodes(const xpath_query& query) const; 522 #endif 523 632 633 // (deprecated: use select_node instead) Select single node by evaluating XPath query. 634 xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const; 635 xpath_node select_single_node(const xpath_query& query) const; 636 637 #endif 638 524 639 // Print subtree using a writer object 525 640 void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const; … … 543 658 attribute_iterator attributes_end() const; 544 659 660 // Range-based for support 661 xml_object_range<xml_node_iterator> children() const; 662 xml_object_range<xml_named_node_iterator> children(const char_t* name) const; 663 xml_object_range<xml_attribute_iterator> attributes() const; 664 545 665 // Get node offset in parsed file/string (in char_t units) for debugging purposes 546 666 ptrdiff_t offset_debug() const; 547 667 548 549 668 // Get hash value (unique for handles to the same object) 669 size_t hash_value() const; 550 670 551 671 // Get internal pointer … … 559 679 #endif 560 680 681 // A helper for working with text inside PCDATA nodes 682 class PUGIXML_CLASS xml_text 683 { 684 friend class xml_node; 685 686 xml_node_struct* _root; 687 688 typedef void (*unspecified_bool_type)(xml_text***); 689 690 explicit xml_text(xml_node_struct* root); 691 692 xml_node_struct* _data_new(); 693 xml_node_struct* _data() const; 694 695 public: 696 // Default constructor. Constructs an empty object. 697 xml_text(); 698 699 // Safe bool conversion operator 700 operator unspecified_bool_type() const; 701 702 // Borland C++ workaround 703 bool operator!() const; 704 705 // Check if text object is empty 706 bool empty() const; 707 708 // Get text, or "" if object is empty 709 const char_t* get() const; 710 711 // Get text, or the default value if object is empty 712 const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; 713 714 // Get text as a number, or the default value if conversion did not succeed or object is empty 715 int as_int(int def = 0) const; 716 unsigned int as_uint(unsigned int def = 0) const; 717 double as_double(double def = 0) const; 718 float as_float(float def = 0) const; 719 720 #ifdef PUGIXML_HAS_LONG_LONG 721 long long as_llong(long long def = 0) const; 722 unsigned long long as_ullong(unsigned long long def = 0) const; 723 #endif 724 725 // Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty 726 bool as_bool(bool def = false) const; 727 728 // Set text (returns false if object is empty or there is not enough memory) 729 bool set(const char_t* rhs); 730 731 // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") 732 bool set(int rhs); 733 bool set(unsigned int rhs); 734 bool set(long rhs); 735 bool set(unsigned long rhs); 736 bool set(double rhs); 737 bool set(float rhs); 738 bool set(bool rhs); 739 740 #ifdef PUGIXML_HAS_LONG_LONG 741 bool set(long long rhs); 742 bool set(unsigned long long rhs); 743 #endif 744 745 // Set text (equivalent to set without error checking) 746 xml_text& operator=(const char_t* rhs); 747 xml_text& operator=(int rhs); 748 xml_text& operator=(unsigned int rhs); 749 xml_text& operator=(long rhs); 750 xml_text& operator=(unsigned long rhs); 751 xml_text& operator=(double rhs); 752 xml_text& operator=(float rhs); 753 xml_text& operator=(bool rhs); 754 755 #ifdef PUGIXML_HAS_LONG_LONG 756 xml_text& operator=(long long rhs); 757 xml_text& operator=(unsigned long long rhs); 758 #endif 759 760 // Get the data node (node_pcdata or node_cdata) for this object 761 xml_node data() const; 762 }; 763 764 #ifdef __BORLANDC__ 765 // Borland C++ workaround 766 bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs); 767 bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs); 768 #endif 769 561 770 // Child node iterator (a bidirectional iterator over a collection of xml_node) 562 771 class PUGIXML_CLASS xml_node_iterator … … 565 774 566 775 private: 567 xml_node _wrap;776 mutable xml_node _wrap; 568 777 xml_node _parent; 569 778 … … 581 790 #endif 582 791 583 792 // Default constructor 584 793 xml_node_iterator(); 585 794 586 795 // Construct an iterator which points to the specified node 587 796 xml_node_iterator(const xml_node& node); 588 797 589 798 // Iterator operators 590 799 bool operator==(const xml_node_iterator& rhs) const; 591 800 bool operator!=(const xml_node_iterator& rhs) const; 592 801 593 xml_node& operator*() ;594 xml_node* operator->() ;802 xml_node& operator*() const; 803 xml_node* operator->() const; 595 804 596 805 const xml_node_iterator& operator++(); … … 607 816 608 817 private: 609 xml_attribute _wrap;818 mutable xml_attribute _wrap; 610 819 xml_node _parent; 611 820 … … 623 832 #endif 624 833 625 834 // Default constructor 626 835 xml_attribute_iterator(); 627 836 628 837 // Construct an iterator which points to the specified attribute 629 838 xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent); 630 839 … … 633 842 bool operator!=(const xml_attribute_iterator& rhs) const; 634 843 635 xml_attribute& operator*() ;636 xml_attribute* operator->() ;844 xml_attribute& operator*() const; 845 xml_attribute* operator->() const; 637 846 638 847 const xml_attribute_iterator& operator++(); … … 643 852 }; 644 853 854 // Named node range helper 855 class PUGIXML_CLASS xml_named_node_iterator 856 { 857 friend class xml_node; 858 859 public: 860 // Iterator traits 861 typedef ptrdiff_t difference_type; 862 typedef xml_node value_type; 863 typedef xml_node* pointer; 864 typedef xml_node& reference; 865 866 #ifndef PUGIXML_NO_STL 867 typedef std::bidirectional_iterator_tag iterator_category; 868 #endif 869 870 // Default constructor 871 xml_named_node_iterator(); 872 873 // Construct an iterator which points to the specified node 874 xml_named_node_iterator(const xml_node& node, const char_t* name); 875 876 // Iterator operators 877 bool operator==(const xml_named_node_iterator& rhs) const; 878 bool operator!=(const xml_named_node_iterator& rhs) const; 879 880 xml_node& operator*() const; 881 xml_node* operator->() const; 882 883 const xml_named_node_iterator& operator++(); 884 xml_named_node_iterator operator++(int); 885 886 const xml_named_node_iterator& operator--(); 887 xml_named_node_iterator operator--(int); 888 889 private: 890 mutable xml_node _wrap; 891 xml_node _parent; 892 const char_t* _name; 893 894 xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name); 895 }; 896 645 897 // Abstract tree walker class (see xml_node::traverse) 646 898 class PUGIXML_CLASS xml_tree_walker … … 650 902 private: 651 903 int _depth; 652 904 653 905 protected: 654 906 // Get current traversal depth 655 907 int depth() const; 656 908 657 909 public: 658 910 xml_tree_walker(); … … 672 924 enum xml_parse_status 673 925 { 674 status_ok = 0, // No error 675 676 status_file_not_found, // File was not found during load_file() 677 status_io_error, // Error reading from file/stream 678 status_out_of_memory, // Could not allocate memory 679 status_internal_error, // Internal error occurred 680 681 status_unrecognized_tag, // Parser could not determine tag type 682 683 status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction 684 status_bad_comment, // Parsing error occurred while parsing comment 685 status_bad_cdata, // Parsing error occurred while parsing CDATA section 686 status_bad_doctype, // Parsing error occurred while parsing document type declaration 687 status_bad_pcdata, // Parsing error occurred while parsing PCDATA section 688 status_bad_start_element, // Parsing error occurred while parsing start element tag 689 status_bad_attribute, // Parsing error occurred while parsing element attribute 690 status_bad_end_element, // Parsing error occurred while parsing end element tag 691 status_end_element_mismatch // There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) 926 status_ok = 0, // No error 927 928 status_file_not_found, // File was not found during load_file() 929 status_io_error, // Error reading from file/stream 930 status_out_of_memory, // Could not allocate memory 931 status_internal_error, // Internal error occurred 932 933 status_unrecognized_tag, // Parser could not determine tag type 934 935 status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction 936 status_bad_comment, // Parsing error occurred while parsing comment 937 status_bad_cdata, // Parsing error occurred while parsing CDATA section 938 status_bad_doctype, // Parsing error occurred while parsing document type declaration 939 status_bad_pcdata, // Parsing error occurred while parsing PCDATA section 940 status_bad_start_element, // Parsing error occurred while parsing start element tag 941 status_bad_attribute, // Parsing error occurred while parsing element attribute 942 status_bad_end_element, // Parsing error occurred while parsing end element tag 943 status_end_element_mismatch,// There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag) 944 945 status_append_invalid_root, // Unable to append nodes since root type is not node_element or node_document (exclusive to xml_node::append_buffer) 946 947 status_no_document_element // Parsing resulted in a document without element nodes 692 948 }; 693 949 … … 704 960 xml_encoding encoding; 705 961 706 962 // Default constructor, initializes object to failed state 707 963 xml_parse_result(); 708 964 … … 721 977 722 978 char _memory[192]; 723 979 724 980 // Non-copyable semantics 725 981 xml_document(const xml_document&); 726 const xml_document& operator=(const xml_document&); 727 728 void create(); 729 void destroy(); 730 731 xml_parse_result load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own); 982 xml_document& operator=(const xml_document&); 983 984 void _create(); 985 void _destroy(); 732 986 733 987 public: … … 738 992 ~xml_document(); 739 993 740 994 // Removes all nodes, leaving the empty document 741 995 void reset(); 742 996 743 997 // Removes all nodes, then copies the entire contents of the specified document 744 998 void reset(const xml_document& proto); 745 999 … … 750 1004 #endif 751 1005 1006 // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied. 1007 xml_parse_result load(const char_t* contents, unsigned int options = parse_default); 1008 752 1009 // Load document from zero-terminated string. No encoding conversions are applied. 753 xml_parse_result load (const char_t* contents, unsigned int options = parse_default);1010 xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default); 754 1011 755 1012 // Load document from file … … 761 1018 762 1019 // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). 763 1020 // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed. 764 1021 xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); 765 1022 766 1023 // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data). 767 1024 // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore). 768 1025 xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); 769 1026 … … 781 1038 bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; 782 1039 783 784 1040 // Get document element 1041 xml_node document_element() const; 785 1042 }; 786 1043 … … 789 1046 enum xpath_value_type 790 1047 { 791 xpath_type_none, 1048 xpath_type_none, // Unknown type (query failed to compile) 792 1049 xpath_type_node_set, // Node set (xpath_node_set) 793 xpath_type_number, 794 xpath_type_string, 795 xpath_type_boolean 796 }; 797 798 1050 xpath_type_number, // Number 1051 xpath_type_string, // String 1052 xpath_type_boolean // Boolean 1053 }; 1054 1055 // XPath parsing result 799 1056 struct PUGIXML_CLASS xpath_parse_result 800 1057 { … … 805 1062 ptrdiff_t offset; 806 1063 807 1064 // Default constructor, initializes object to failed state 808 1065 xpath_parse_result(); 809 1066 … … 824 1081 xpath_variable* _next; 825 1082 826 xpath_variable( );1083 xpath_variable(xpath_value_type type); 827 1084 828 1085 // Non-copyable semantics 829 1086 xpath_variable(const xpath_variable&); 830 1087 xpath_variable& operator=(const xpath_variable&); 831 832 public: 833 1088 1089 public: 1090 // Get variable name 834 1091 const char_t* name() const; 835 1092 836 1093 // Get variable type 837 1094 xpath_value_type type() const; 838 1095 839 1096 // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error 840 1097 bool get_boolean() const; 841 1098 double get_number() const; … … 843 1100 const xpath_node_set& get_node_set() const; 844 1101 845 1102 // Set variable value; no type conversion is performed, false is returned on type mismatch error 846 1103 bool set(bool value); 847 1104 bool set(double value); … … 856 1113 xpath_variable* _data[64]; 857 1114 858 // Non-copyable semantics 859 xpath_variable_set(const xpath_variable_set&); 860 xpath_variable_set& operator=(const xpath_variable_set&); 861 862 xpath_variable* find(const char_t* name) const; 863 864 public: 865 // Default constructor/destructor 1115 void _assign(const xpath_variable_set& rhs); 1116 void _swap(xpath_variable_set& rhs); 1117 1118 xpath_variable* _find(const char_t* name) const; 1119 1120 static bool _clone(xpath_variable* var, xpath_variable** out_result); 1121 static void _destroy(xpath_variable* var); 1122 1123 public: 1124 // Default constructor/destructor 866 1125 xpath_variable_set(); 867 1126 ~xpath_variable_set(); 868 1127 869 // Add a new variable or get the existing one, if the types match 1128 // Copy constructor/assignment operator 1129 xpath_variable_set(const xpath_variable_set& rhs); 1130 xpath_variable_set& operator=(const xpath_variable_set& rhs); 1131 1132 #ifdef PUGIXML_HAS_MOVE 1133 // Move semantics support 1134 xpath_variable_set(xpath_variable_set&& rhs); 1135 xpath_variable_set& operator=(xpath_variable_set&& rhs); 1136 #endif 1137 1138 // Add a new variable or get the existing one, if the types match 870 1139 xpath_variable* add(const char_t* name, xpath_value_type type); 871 1140 872 1141 // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch 873 1142 bool set(const char_t* name, bool value); 874 1143 bool set(const char_t* name, double value); … … 876 1145 bool set(const char_t* name, const xpath_node_set& value); 877 1146 878 1147 // Get existing variable by name 879 1148 xpath_variable* get(const char_t* name); 880 1149 const xpath_variable* get(const char_t* name) const; … … 888 1157 xpath_parse_result _result; 889 1158 890 typedef void* xpath_query::*unspecified_bool_type;1159 typedef void (*unspecified_bool_type)(xpath_query***); 891 1160 892 1161 // Non-copyable semantics … … 895 1164 896 1165 public: 897 898 1166 // Construct a compiled object from XPath expression. 1167 // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors. 899 1168 explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0); 1169 1170 // Constructor 1171 xpath_query(); 900 1172 901 1173 // Destructor 902 1174 ~xpath_query(); 903 1175 1176 #ifdef PUGIXML_HAS_MOVE 1177 // Move semantics support 1178 xpath_query(xpath_query&& rhs); 1179 xpath_query& operator=(xpath_query&& rhs); 1180 #endif 1181 904 1182 // Get query expression return type 905 1183 xpath_value_type return_type() const; 906 1184 907 1185 // Evaluate expression as boolean value in the specified context; performs type conversion if necessary. 908 1186 // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. 909 1187 bool evaluate_boolean(const xpath_node& n) const; 910 1188 911 1189 // Evaluate expression as double value in the specified context; performs type conversion if necessary. 912 1190 // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. 913 1191 double evaluate_number(const xpath_node& n) const; 914 1192 915 1193 #ifndef PUGIXML_NO_STL 916 1194 // Evaluate expression as string value in the specified context; performs type conversion if necessary. 917 1195 // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. 918 1196 string_t evaluate_string(const xpath_node& n) const; 919 1197 #endif 920 1198 921 1199 // Evaluate expression as string value in the specified context; performs type conversion if necessary. 922 923 924 1200 // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero). 1201 // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors. 1202 // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead. 925 1203 size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const; 926 1204 927 1205 // Evaluate expression as node set in the specified context. 928 929 1206 // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. 1207 // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead. 930 1208 xpath_node_set evaluate_node_set(const xpath_node& n) const; 1209 1210 // Evaluate expression as node set in the specified context. 1211 // Return first node in document order, or empty node if node set is empty. 1212 // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors. 1213 // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node instead. 1214 xpath_node evaluate_node(const xpath_node& n) const; 931 1215 932 1216 // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode) … … 936 1220 operator unspecified_bool_type() const; 937 1221 938 1222 // Borland C++ workaround 939 1223 bool operator!() const; 940 1224 }; 941 1225 942 1226 #ifndef PUGIXML_NO_EXCEPTIONS 943 1227 // XPath exception class … … 952 1236 953 1237 // Get error message 954 virtual const char* what() const throw() ;955 956 1238 virtual const char* what() const throw() PUGIXML_OVERRIDE; 1239 1240 // Get parse result 957 1241 const xpath_parse_result& result() const; 958 1242 }; 959 1243 #endif 960 1244 961 1245 // XPath node class (either xml_node or xml_attribute) 962 1246 class PUGIXML_CLASS xpath_node … … 965 1249 xml_node _node; 966 1250 xml_attribute _attribute; 967 968 typedef xml_node xpath_node::*unspecified_bool_type;1251 1252 typedef void (*unspecified_bool_type)(xpath_node***); 969 1253 970 1254 public: 971 1255 // Default constructor; constructs empty XPath node 972 1256 xpath_node(); 973 1257 974 1258 // Construct XPath node from XML node/attribute 975 1259 xpath_node(const xml_node& node); … … 979 1263 xml_node node() const; 980 1264 xml_attribute attribute() const; 981 1265 982 1266 // Get parent of contained node/attribute 983 1267 xml_node parent() const; 984 1268 985 1269 // Safe bool conversion operator 986 1270 operator unspecified_bool_type() const; 987 988 989 1271 1272 // Borland C++ workaround 1273 bool operator!() const; 990 1274 991 1275 // Comparison operators … … 1011 1295 type_sorted_reverse // Sorted by document order (descending) 1012 1296 }; 1013 1297 1014 1298 // Constant iterator type 1015 1299 typedef const xpath_node* const_iterator; 1016 1300 1301 // We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work 1302 typedef const xpath_node* iterator; 1303 1017 1304 // Default constructor. Constructs empty set. 1018 1305 xpath_node_set(); … … 1023 1310 // Destructor 1024 1311 ~xpath_node_set(); 1025 1312 1026 1313 // Copy constructor/assignment operator 1027 1314 xpath_node_set(const xpath_node_set& ns); 1028 1315 xpath_node_set& operator=(const xpath_node_set& ns); 1029 1316 1317 #ifdef PUGIXML_HAS_MOVE 1318 // Move semantics support 1319 xpath_node_set(xpath_node_set&& rhs); 1320 xpath_node_set& operator=(xpath_node_set&& rhs); 1321 #endif 1322 1030 1323 // Get collection type 1031 1324 type_t type() const; 1032 1325 1033 1326 // Get collection size 1034 1327 size_t size() const; 1035 1328 1036 1329 // Indexing operator 1037 1330 const xpath_node& operator[](size_t index) const; 1038 1331 1039 1332 // Collection iterators 1040 1333 const_iterator begin() const; … … 1043 1336 // Sort the collection in ascending/descending order by document order 1044 1337 void sort(bool reverse = false); 1045 1338 1046 1339 // Get first node in the collection by document order 1047 1340 xpath_node first() const; 1048 1341 1049 1342 // Check if collection is empty 1050 1343 bool empty() const; 1051 1344 1052 1345 private: 1053 1346 type_t _type; 1054 1347 1055 1348 xpath_node _storage; 1056 1349 1057 1350 xpath_node* _begin; 1058 1351 xpath_node* _end; 1059 1352 1060 void _assign(const_iterator begin, const_iterator end); 1353 void _assign(const_iterator begin, const_iterator end, type_t type); 1354 void _move(xpath_node_set& rhs); 1061 1355 }; 1062 1356 #endif … … 1066 1360 std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const wchar_t* str); 1067 1361 std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >& str); 1068 1362 1069 1363 // Convert UTF8 to wide string 1070 1364 std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const char* str); … … 1074 1368 // Memory allocation function interface; returns pointer to allocated memory or NULL on failure 1075 1369 typedef void* (*allocation_function)(size_t size); 1076 1370 1077 1371 // Memory deallocation function interface 1078 1079 1080 1081 1082 1083 1084 1085 1372 typedef void (*deallocation_function)(void* ptr); 1373 1374 // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions. 1375 void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate); 1376 1377 // Get current memory management functions 1378 allocation_function PUGIXML_FUNCTION get_memory_allocation_function(); 1379 deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function(); 1086 1380 } 1087 1381 … … 1092 1386 std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&); 1093 1387 std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&); 1388 std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&); 1094 1389 } 1095 1390 #endif … … 1101 1396 std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&); 1102 1397 std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&); 1398 std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&); 1103 1399 } 1104 1400 #endif … … 1106 1402 #endif 1107 1403 1404 // Make sure implementation is included in header-only mode 1405 // Use macro expansion in #include to work around QMake (QTBUG-11923) 1406 #if defined(PUGIXML_HEADER_ONLY) && !defined(PUGIXML_SOURCE) 1407 # define PUGIXML_SOURCE "pugixml.cpp" 1408 # include PUGIXML_SOURCE 1409 #endif 1410 1108 1411 /** 1109 * Copyright (c) 2006-201 0Arseny Kapoulkine1412 * Copyright (c) 2006-2016 Arseny Kapoulkine 1110 1413 * 1111 1414 * Permission is hereby granted, free of charge, to any person … … 1120 1423 * The above copyright notice and this permission notice shall be 1121 1424 * included in all copies or substantial portions of the Software. 1122 * 1425 * 1123 1426 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1124 1427 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -
ThirdParty/vmg/src/thirdparty/pugixml/readme.txt
r6798a5 r33a694 1 pugixml 1. 0- an XML processing library1 pugixml 1.8 - an XML processing library 2 2 3 Copyright (C) 2006-201 0, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)3 Copyright (C) 2006-2016, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) 4 4 Report bugs and download new versions at http://pugixml.org/ 5 5 … … 29 29 This library is distributed under the MIT License: 30 30 31 Copyright (c) 2006-201 0Arseny Kapoulkine31 Copyright (c) 2006-2016 Arseny Kapoulkine 32 32 33 33 Permission is hereby granted, free of charge, to any person
Note:
See TracChangeset
for help on using the changeset viewer.