summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pugixml.cpp143
-rw-r--r--src/pugixml.hpp21
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