[PATCH 3/4] msxml3/mxwriter: Flush internal buffer as soon as it's filled
Nikolay Sivov
nsivov at codeweavers.com
Sun Mar 27 09:23:02 CDT 2016
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/msxml3/mxwriter.c | 226 +++++++++++++++++++++++--------------------------
1 file changed, 108 insertions(+), 118 deletions(-)
diff --git a/dlls/msxml3/mxwriter.c b/dlls/msxml3/mxwriter.c
index 23a8fd1..1840fa1 100644
--- a/dlls/msxml3/mxwriter.c
+++ b/dlls/msxml3/mxwriter.c
@@ -99,13 +99,6 @@ static const struct xml_encoding_data xml_encoding_map[] = {
typedef enum
{
- OutputBuffer_Native = 0x001,
- OutputBuffer_Encoded = 0x010,
- OutputBuffer_Both = 0x100
-} output_mode;
-
-typedef enum
-{
MXWriter_BOM = 0,
MXWriter_DisableEscaping,
MXWriter_Indent,
@@ -130,7 +123,6 @@ typedef struct
typedef struct
{
- encoded_buffer utf16;
encoded_buffer encoded;
UINT code_page;
UINT utf16_total; /* total number of bytes written since last buffer reinitialization */
@@ -173,7 +165,6 @@ typedef struct
BSTR element;
IStream *dest;
- ULONG dest_written;
output_buffer buffer;
} mxwriter;
@@ -293,21 +284,10 @@ static HRESULT init_output_buffer(xml_encoding encoding, output_buffer *buffer)
if (hr != S_OK)
return hr;
- hr = init_encoded_buffer(&buffer->utf16);
+ hr = init_encoded_buffer(&buffer->encoded);
if (hr != S_OK)
return hr;
- /* currently we always create a default output buffer that is UTF-16 only,
- but it's possible to allocate with specific encoding too */
- if (encoding != XmlEncoding_UTF16) {
- hr = init_encoded_buffer(&buffer->encoded);
- if (hr != S_OK) {
- free_encoded_buffer(&buffer->utf16);
- return hr;
- }
- }
- else
- memset(&buffer->encoded, 0, sizeof(buffer->encoded));
list_init(&buffer->blocks);
buffer->utf16_total = 0;
@@ -319,7 +299,6 @@ static void free_output_buffer(output_buffer *buffer)
encoded_buffer *cur, *cur2;
free_encoded_buffer(&buffer->encoded);
- free_encoded_buffer(&buffer->utf16);
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &buffer->blocks, encoded_buffer, entry)
{
@@ -329,23 +308,93 @@ static void free_output_buffer(output_buffer *buffer)
}
}
-static void grow_buffer(encoded_buffer *buffer, int length)
+static HRESULT write_output_buffer(mxwriter *writer, const WCHAR *data, int len)
{
- /* grow if needed, plus 4 bytes to be sure null terminator will fit in */
- if (buffer->allocated < buffer->written + length + 4)
+ output_buffer *buffer = &writer->buffer;
+ encoded_buffer *buff;
+ unsigned int written;
+ int src_len;
+
+ if (!len || !*data)
+ return S_OK;
+
+ src_len = len == -1 ? strlenW(data) : len;
+ if (writer->dest)
{
- int grown_size = max(2*buffer->allocated, buffer->allocated + length);
- buffer->data = heap_realloc(buffer->data, grown_size);
- buffer->allocated = grown_size;
- }
-}
+ buff = &buffer->encoded;
-static HRESULT write_output_buffer_mode(mxwriter *writer, output_mode mode, const WCHAR *data, int len)
-{
- output_buffer *buffer = &writer->buffer;
- int length;
- char *ptr;
+ if (buffer->code_page == ~0)
+ {
+ unsigned int avail = buff->allocated - buff->written;
+
+ src_len *= sizeof(WCHAR);
+ written = min(avail, src_len);
+
+ /* fill internal buffer first */
+ if (avail)
+ {
+ memcpy(buff->data + buff->written, data, written);
+ data += written / sizeof(WCHAR);
+ buff->written += written;
+ avail -= written;
+ src_len -= written;
+ }
+
+ if (!avail)
+ {
+ IStream_Write(writer->dest, buff->data, buff->written, &written);
+ buff->written = 0;
+ if (src_len >= buff->allocated)
+ IStream_Write(writer->dest, data, src_len, &written);
+ else if (src_len)
+ {
+ memcpy(buff->data, data, src_len);
+ buff->written += src_len;
+ }
+ }
+ }
+ else
+ {
+ unsigned int avail = buff->allocated - buff->written;
+ int length;
+
+ length = WideCharToMultiByte(buffer->code_page, 0, data, src_len, NULL, 0, NULL, NULL);
+ if (avail >= length)
+ {
+ length = WideCharToMultiByte(buffer->code_page, 0, data, src_len, buff->data + buff->written, length, NULL, NULL);
+ buff->written += length;
+ }
+ else
+ {
+ /* drain what we go so far */
+ if (buff->written)
+ {
+ IStream_Write(writer->dest, buff->data, buff->written, &written);
+ buff->written = 0;
+ avail = buff->allocated;
+ }
+ if (avail >= length)
+ {
+ length = WideCharToMultiByte(buffer->code_page, 0, data, src_len, buff->data + buff->written, length, NULL, NULL);
+ buff->written += length;
+ }
+ else
+ {
+ char *mb;
+
+ /* if current chunk is larger than total buffer size, convert it at once using temporary allocated buffer */
+ mb = heap_alloc(length);
+ if (!mb)
+ return E_OUTOFMEMORY;
+
+ length = WideCharToMultiByte(buffer->code_page, 0, data, src_len, mb, length, NULL, NULL);
+ IStream_Write(writer->dest, mb, length, &written);
+ heap_free(mb);
+ }
+ }
+ }
+ }
/* When writer has no output set we have to accumulate everything to return it later in a form of BSTR.
To achieve that:
@@ -354,33 +403,30 @@ static HRESULT write_output_buffer_mode(mxwriter *writer, output_mode mode, cons
but are linked together, with head pointing to first allocated buffer after initial one got filled;
- later during get_output() contents are concatenated by copying one after another to destination BSTR buffer,
that's returned to the client. */
- if (!writer->dest && (mode & (OutputBuffer_Native | OutputBuffer_Both)))
+ else
{
- encoded_buffer *buff;
-
/* select last used block */
if (list_empty(&buffer->blocks))
- buff = &buffer->utf16;
+ buff = &buffer->encoded;
else
buff = LIST_ENTRY(list_tail(&buffer->blocks), encoded_buffer, entry);
- length = (len == -1 ? strlenW(data) : len) * sizeof(WCHAR);
-
- while (length)
+ src_len *= sizeof(WCHAR);
+ while (src_len)
{
unsigned int avail = buff->allocated - buff->written;
- unsigned int written = min(avail, length);
+ unsigned int written = min(avail, src_len);
if (avail)
{
memcpy(buff->data + buff->written, data, written);
buff->written += written;
buffer->utf16_total += written;
- length -= written;
+ src_len -= written;
}
/* alloc new block if needed and retry */
- if (length)
+ if (src_len)
{
encoded_buffer *next = heap_alloc(sizeof(*next));
HRESULT hr;
@@ -394,47 +440,11 @@ static HRESULT write_output_buffer_mode(mxwriter *writer, output_mode mode, cons
buff = next;
}
}
-
- return S_OK;
- }
-
- if (mode & (OutputBuffer_Encoded | OutputBuffer_Both)) {
- if (buffer->code_page != ~0)
- {
- length = WideCharToMultiByte(buffer->code_page, 0, data, len, NULL, 0, NULL, NULL);
- grow_buffer(&buffer->encoded, length);
- ptr = buffer->encoded.data + buffer->encoded.written;
- length = WideCharToMultiByte(buffer->code_page, 0, data, len, ptr, length, NULL, NULL);
- buffer->encoded.written += len == -1 ? length-1 : length;
- }
- }
-
- if (mode & (OutputBuffer_Native | OutputBuffer_Both)) {
- /* WCHAR data just copied */
- length = len == -1 ? strlenW(data) : len;
- if (length)
- {
- length *= sizeof(WCHAR);
-
- grow_buffer(&buffer->utf16, length);
- ptr = buffer->utf16.data + buffer->utf16.written;
-
- memcpy(ptr, data, length);
- buffer->utf16.written += length;
- ptr += length;
- /* null termination */
- memset(ptr, 0, sizeof(WCHAR));
- }
}
return S_OK;
}
-static HRESULT write_output_buffer(mxwriter *writer, const WCHAR *data, int len)
-{
- return write_output_buffer_mode(writer, OutputBuffer_Both, data, len);
-}
-
static HRESULT write_output_buffer_quoted(mxwriter *writer, const WCHAR *data, int len)
{
write_output_buffer(writer, quotW, 1);
@@ -449,7 +459,6 @@ static void close_output_buffer(mxwriter *writer)
{
encoded_buffer *cur, *cur2;
- heap_free(writer->buffer.utf16.data);
heap_free(writer->buffer.encoded.data);
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &writer->buffer.blocks, encoded_buffer, entry)
@@ -459,7 +468,6 @@ static void close_output_buffer(mxwriter *writer)
heap_free(cur);
}
- init_encoded_buffer(&writer->buffer.utf16);
init_encoded_buffer(&writer->buffer.encoded);
get_code_page(writer->xml_enc, &writer->buffer.code_page);
writer->buffer.utf16_total = 0;
@@ -553,9 +561,10 @@ static void write_prolog_buffer(mxwriter *writer)
/* encoding */
write_output_buffer(writer, encodingW, sizeof(encodingW)/sizeof(WCHAR));
- /* always write UTF-16 to WCHAR buffer */
- write_output_buffer_mode(writer, OutputBuffer_Native, utf16W, sizeof(utf16W)/sizeof(WCHAR) - 1);
- write_output_buffer_mode(writer, OutputBuffer_Encoded, writer->encoding, -1);
+ if (writer->dest)
+ write_output_buffer(writer, writer->encoding, -1);
+ else
+ write_output_buffer(writer, utf16W, sizeof(utf16W)/sizeof(WCHAR) - 1);
write_output_buffer(writer, quotW, 1);
/* standalone */
@@ -572,43 +581,26 @@ static void write_prolog_buffer(mxwriter *writer)
/* Attempts to the write data from the mxwriter's buffer to
* the destination stream (if there is one).
*/
-static HRESULT write_data_to_stream(mxwriter *This)
+static HRESULT write_data_to_stream(mxwriter *writer)
{
- encoded_buffer *buffer;
+ encoded_buffer *buffer = &writer->buffer.encoded;
ULONG written = 0;
- HRESULT hr;
- if (!This->dest)
+ if (!writer->dest)
return S_OK;
- if (This->xml_enc != XmlEncoding_UTF16)
- buffer = &This->buffer.encoded;
+ if (buffer->written == 0)
+ {
+ if (writer->xml_enc == XmlEncoding_UTF8)
+ IStream_Write(writer->dest, buffer->data, 0, &written);
+ }
else
- buffer = &This->buffer.utf16;
-
- if (This->dest_written > buffer->written) {
- ERR("Failed sanity check! Not sure what to do... (%d > %d)\n", This->dest_written, buffer->written);
- return E_FAIL;
- } else if (This->dest_written == buffer->written && This->xml_enc != XmlEncoding_UTF8)
- /* Windows seems to make an empty write call when the encoding is UTF-8 and
- * all the data has been written to the stream. It doesn't seem make this call
- * for any other encodings.
- */
- return S_OK;
-
- /* Write the current content from the output buffer into 'dest'.
- * TODO: Check what Windows does if the IStream doesn't write all of
- * the data we give it at once.
- */
- hr = IStream_Write(This->dest, buffer->data+This->dest_written,
- buffer->written-This->dest_written, &written);
- if (FAILED(hr)) {
- WARN("Failed to write data to IStream (0x%08x)\n", hr);
- return hr;
+ {
+ IStream_Write(writer->dest, buffer->data, buffer->written, &written);
+ buffer->written = 0;
}
- This->dest_written += written;
- return hr;
+ return S_OK;
}
/* Newly added element start tag left unclosed cause for empty elements
@@ -678,7 +670,6 @@ static inline HRESULT flush_output_buffer(mxwriter *This)
static inline void reset_output_buffer(mxwriter *This)
{
close_output_buffer(This);
- This->dest_written = 0;
}
static HRESULT writer_set_property(mxwriter *writer, mxwriter_prop property, VARIANT_BOOL value)
@@ -967,7 +958,7 @@ static HRESULT WINAPI mxwriter_get_output(IMXWriter *iface, VARIANT *dest)
return E_OUTOFMEMORY;
dest_ptr = (char*)V_BSTR(dest);
- buff = &This->buffer.utf16;
+ buff = &This->buffer.encoded;
if (buff->written)
{
@@ -2607,7 +2598,6 @@ HRESULT MXWriter_create(MSXML_VERSION version, void **ppObj)
This->newline = FALSE;
This->dest = NULL;
- This->dest_written = 0;
hr = init_output_buffer(This->xml_enc, &This->buffer);
if (hr != S_OK) {
--
2.8.0.rc3
More information about the wine-patches
mailing list