diff options
-rw-r--r-- | src/pugixml.cpp | 143 | ||||
-rw-r--r-- | src/pugixml.hpp | 21 |
2 files changed, 138 insertions, 26 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 0b76d1f..24b4a6a 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1887,6 +1887,8 @@ namespace } THROW_ERROR(status_bad_doctype, s); + + return s; } char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel) @@ -2975,6 +2977,40 @@ namespace } } + xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding) + { + if (!file) return make_parse_result(status_file_not_found); + + fseek(file, 0, SEEK_END); + long length = ftell(file); + fseek(file, 0, SEEK_SET); + + if (length < 0) + { + fclose(file); + return make_parse_result(status_io_error); + } + + char* s = static_cast<char*>(global_allocate(length > 0 ? length : 1)); + + if (!s) + { + fclose(file); + return make_parse_result(status_out_of_memory); + } + + size_t read = fread(s, 1, (size_t)length, file); + fclose(file); + + if (read != (size_t)length) + { + global_deallocate(s); + return make_parse_result(status_io_error); + } + + return doc.load_buffer_inplace_own(s, length, options, encoding); + } + #ifndef PUGIXML_NO_STL template <typename T> xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding) { @@ -3007,6 +3043,67 @@ namespace return doc.load_buffer_inplace_own(buffer.release(), actual_length * sizeof(T), options, encoding); } #endif + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) + FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + { + return _wfopen(path, mode); + } +#else + char* convert_path_heap(const wchar_t* str) + { + assert(str); + + STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); + + size_t length = wcslen(str); + + // first pass: get length in utf8 characters + size_t size = sizeof(wchar_t) == 2 ? + utf_decoder<utf8_counter>::decode_utf16_block(reinterpret_cast<const uint16_t*>(str), length, 0) : + utf_decoder<utf8_counter>::decode_utf32_block(reinterpret_cast<const uint32_t*>(str), length, 0); + + // allocate resulting string + char* result = static_cast<char*>(global_allocate(size + 1)); + if (!result) return 0; + + // second pass: convert to utf8 + if (size > 0) + { + uint8_t* begin = reinterpret_cast<uint8_t*>(result); + uint8_t* end = sizeof(wchar_t) == 2 ? + utf_decoder<utf8_writer>::decode_utf16_block(reinterpret_cast<const uint16_t*>(str), length, begin) : + utf_decoder<utf8_writer>::decode_utf32_block(reinterpret_cast<const uint32_t*>(str), length, begin); + + assert(begin + size == end); + (void)!end; + } + + // zero-terminate + result[size] = 0; + + return result; + } + + FILE* open_file_wide(const wchar_t* path, const wchar_t* mode) + { + // there is no standard function to open wide paths, so our best bet is to try utf8 path + char* path_utf8 = convert_path_heap(path); + if (!path_utf8) return 0; + + // convert mode to ASCII (we mirror _wfopen interface) + char mode_ascii[4] = {0}; + for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]); + + // try to open the utf8 path + FILE* result = fopen(path_utf8, mode_ascii); + + // free dummy buffer + global_deallocate(path_utf8); + + return result; + } +#endif } namespace pugi @@ -4255,36 +4352,17 @@ namespace pugi reset(); FILE* file = fopen(path, "rb"); - if (!file) return make_parse_result(status_file_not_found); - - fseek(file, 0, SEEK_END); - long length = ftell(file); - fseek(file, 0, SEEK_SET); - if (length < 0) - { - fclose(file); - return make_parse_result(status_io_error); - } - - char* s = static_cast<char*>(global_allocate(length > 0 ? length : 1)); + return load_file_impl(*this, file, options, encoding); + } - if (!s) - { - fclose(file); - return make_parse_result(status_out_of_memory); - } + xml_parse_result xml_document::load_file(const wchar_t* path, unsigned int options, xml_encoding encoding) + { + reset(); - size_t read = fread(s, 1, (size_t)length, file); - fclose(file); + FILE* file = open_file_wide(path, L"rb"); - if (read != (size_t)length) - { - global_deallocate(s); - return make_parse_result(status_io_error); - } - - return load_buffer_inplace_own(s, length, options, encoding); + return load_file_impl(*this, file, options, encoding); } xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own) @@ -4377,6 +4455,19 @@ namespace pugi return true; } + bool xml_document::save_file(const wchar_t* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const + { + FILE* file = open_file_wide(path, L"wb"); + if (!file) return false; + + xml_writer_file writer(file); + save(writer, indent, flags, encoding); + + fclose(file); + + return true; + } + #ifndef PUGIXML_NO_STL std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) { diff --git a/src/pugixml.hpp b/src/pugixml.hpp index b6f1710..12b8f49 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -1673,6 +1673,16 @@ namespace pugi xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); /** + * Load document from file + * + * \param path - file path + * \param options - parsing options + * \param encoding - source data encoding + * \return parsing result + */ + xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); + + /** * Load document from buffer * * \param contents - buffer contents @@ -1751,6 +1761,17 @@ namespace pugi * \return success flag */ bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const; + + /** + * Save XML to file + * + * \param path - file path + * \param indent - indentation string + * \param flags - formatting flags + * \param encoding - encoding used for writing + * \return success flag + */ + 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; }; #ifndef PUGIXML_NO_XPATH |