diff options
| -rw-r--r-- | src/pugixml.cpp | 34 | 
1 files changed, 33 insertions, 1 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp index c9b0046..c6f74e7 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1327,12 +1327,40 @@ namespace  	}  #endif +	inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target) +	{ +		assert(target); +		size_t target_length = impl::strlen(target); + +		// always reuse document buffer memory if possible +		if (!allocated) return target_length >= length; + +		// reuse heap memory if waste is not too great +		const size_t reuse_threshold = 32; + +		return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); +	} +  	bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source)  	{  		size_t source_length = impl::strlen(source); -		if (dest && impl::strlen(dest) >= source_length) +		if (source_length == 0) +		{ +			// empty string and null pointer are equivalent, so just deallocate old memory +			xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator; + +			if (header & header_mask) alloc->deallocate_string(dest); +			 +			// mark the string as not allocated +			dest = 0; +			header &= ~header_mask; + +			return true; +		} +		else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest))  		{ +			// we can reuse old buffer, so just copy the new data (including zero terminator)  			memcpy(dest, source, (source_length + 1) * sizeof(char_t));  			return true; @@ -1341,13 +1369,17 @@ namespace  		{  			xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator; +			// allocate new buffer  			char_t* buf = alloc->allocate_string(source_length + 1);  			if (!buf) return false; +			// copy the string (including zero terminator)  			memcpy(buf, source, (source_length + 1) * sizeof(char_t)); +			// deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)  			if (header & header_mask) alloc->deallocate_string(dest); +			// the string is now allocated, so set the flag  			dest = buf;  			header |= header_mask;  | 
