webservices: Add support for retrieving the output buffer.
[wine/multimedia.git] / dlls / webservices / writer.c
blobb56c718ddd53a7b33ea2ca095a0edbb19e05cb2a
1 /*
2 * Copyright 2015 Hans Leidekker for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "webservices.h"
25 #include "wine/debug.h"
26 #include "wine/list.h"
27 #include "webservices_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(webservices);
31 static const struct
33 ULONG size;
34 BOOL readonly;
36 writer_props[] =
38 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_DEPTH */
39 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_FRAGMENT */
40 { sizeof(ULONG), FALSE }, /* WS_XML_READER_PROPERTY_MAX_ATTRIBUTES */
41 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_WRITE_DECLARATION */
42 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_INDENT */
43 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE */
44 { sizeof(WS_CHARSET), FALSE }, /* WS_XML_WRITER_PROPERTY_CHARSET */
45 { sizeof(WS_BUFFERS), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFERS */
46 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE */
47 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_BYTES */
48 { sizeof(BOOL), TRUE }, /* WS_XML_WRITER_PROPERTY_IN_ATTRIBUTE */
49 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE */
50 { sizeof(WS_BYTES), FALSE }, /* WS_XML_WRITER_PROPERTY_INITIAL_BUFFER */
51 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_ALLOW_INVALID_CHARACTER_REFERENCES */
52 { sizeof(ULONG), FALSE }, /* WS_XML_WRITER_PROPERTY_MAX_NAMESPACES */
53 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_WRITTEN */
54 { sizeof(ULONG), TRUE }, /* WS_XML_WRITER_PROPERTY_BYTES_TO_CLOSE */
55 { sizeof(BOOL), FALSE }, /* WS_XML_WRITER_PROPERTY_COMPRESS_EMPTY_ELEMENTS */
56 { sizeof(BOOL), FALSE } /* WS_XML_WRITER_PROPERTY_EMIT_UNCOMPRESSED_EMPTY_ELEMENTS */
59 enum writer_state
61 WRITER_STATE_INITIAL,
62 WRITER_STATE_STARTELEMENT,
63 WRITER_STATE_STARTENDELEMENT,
64 WRITER_STATE_STARTATTRIBUTE,
65 WRITER_STATE_ENDSTARTELEMENT,
66 WRITER_STATE_ENDELEMENT
69 struct writer
71 ULONG write_pos;
72 char *write_bufptr;
73 enum writer_state state;
74 struct node *root;
75 struct node *current;
76 WS_XML_WRITER_OUTPUT_TYPE output_type;
77 struct xmlbuf *output_buf;
78 WS_HEAP *output_heap;
79 ULONG prop_count;
80 WS_XML_WRITER_PROPERTY prop[sizeof(writer_props)/sizeof(writer_props[0])];
83 static struct writer *alloc_writer(void)
85 static const ULONG count = sizeof(writer_props)/sizeof(writer_props[0]);
86 struct writer *ret;
87 ULONG i, size = sizeof(*ret) + count * sizeof(WS_XML_WRITER_PROPERTY);
88 char *ptr;
90 for (i = 0; i < count; i++) size += writer_props[i].size;
91 if (!(ret = heap_alloc_zero( size ))) return NULL;
93 ptr = (char *)&ret->prop[count];
94 for (i = 0; i < count; i++)
96 ret->prop[i].value = ptr;
97 ret->prop[i].valueSize = writer_props[i].size;
98 ptr += ret->prop[i].valueSize;
100 ret->prop_count = count;
101 return ret;
104 static HRESULT set_writer_prop( struct writer *writer, WS_XML_WRITER_PROPERTY_ID id, const void *value,
105 ULONG size )
107 if (id >= writer->prop_count || size != writer_props[id].size || writer_props[id].readonly)
108 return E_INVALIDARG;
110 memcpy( writer->prop[id].value, value, size );
111 return S_OK;
114 static HRESULT get_writer_prop( struct writer *writer, WS_XML_WRITER_PROPERTY_ID id, void *buf, ULONG size )
116 if (id >= writer->prop_count || size != writer_props[id].size)
117 return E_INVALIDARG;
119 memcpy( buf, writer->prop[id].value, writer->prop[id].valueSize );
120 return S_OK;
123 static void free_writer( struct writer *writer )
125 destroy_nodes( writer->root );
126 WsFreeHeap( writer->output_heap );
127 heap_free( writer );
130 static void write_insert_eof( struct writer *writer, struct node *eof )
132 if (!writer->root) writer->root = eof;
133 else
135 eof->parent = writer->root;
136 list_add_tail( &writer->root->children, &eof->entry );
138 writer->current = eof;
141 static void write_insert_bof( struct writer *writer, struct node *bof )
143 writer->root->parent = bof;
144 list_add_tail( &bof->children, &writer->root->entry );
145 writer->current = writer->root = bof;
148 static void write_insert_node( struct writer *writer, struct node *node )
150 node->parent = writer->current;
151 if (writer->current == writer->root)
153 struct list *eof = list_tail( &writer->root->children );
154 list_add_before( eof, &node->entry );
156 else list_add_tail( &writer->current->children, &node->entry );
157 writer->current = node;
160 static HRESULT write_init_state( struct writer *writer )
162 struct node *node;
164 destroy_nodes( writer->root );
165 writer->root = NULL;
166 if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
167 write_insert_eof( writer, node );
168 writer->state = WRITER_STATE_INITIAL;
169 return S_OK;
172 /**************************************************************************
173 * WsCreateWriter [webservices.@]
175 HRESULT WINAPI WsCreateWriter( const WS_XML_WRITER_PROPERTY *properties, ULONG count,
176 WS_XML_WRITER **handle, WS_ERROR *error )
178 struct writer *writer;
179 ULONG i, max_depth = 32, max_attrs = 128, trim_size = 4096, max_size = 65536, max_ns = 32;
180 WS_CHARSET charset = WS_CHARSET_UTF8;
181 HRESULT hr;
183 TRACE( "%p %u %p %p\n", properties, count, handle, error );
184 if (error) FIXME( "ignoring error parameter\n" );
186 if (!handle) return E_INVALIDARG;
187 if (!(writer = alloc_writer())) return E_OUTOFMEMORY;
189 set_writer_prop( writer, WS_XML_WRITER_PROPERTY_MAX_DEPTH, &max_depth, sizeof(max_depth) );
190 set_writer_prop( writer, WS_XML_WRITER_PROPERTY_MAX_ATTRIBUTES, &max_attrs, sizeof(max_attrs) );
191 set_writer_prop( writer, WS_XML_WRITER_PROPERTY_BUFFER_TRIM_SIZE, &trim_size, sizeof(trim_size) );
192 set_writer_prop( writer, WS_XML_WRITER_PROPERTY_CHARSET, &charset, sizeof(charset) );
193 set_writer_prop( writer, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
194 set_writer_prop( writer, WS_XML_WRITER_PROPERTY_MAX_MIME_PARTS_BUFFER_SIZE, &max_size, sizeof(max_size) );
195 set_writer_prop( writer, WS_XML_WRITER_PROPERTY_MAX_NAMESPACES, &max_ns, sizeof(max_ns) );
197 for (i = 0; i < count; i++)
199 hr = set_writer_prop( writer, properties[i].id, properties[i].value, properties[i].valueSize );
200 if (hr != S_OK)
202 free_writer( writer );
203 return hr;
207 hr = get_writer_prop( writer, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE, &max_size, sizeof(max_size) );
208 if (hr != S_OK)
210 free_writer( writer );
211 return hr;
214 hr = WsCreateHeap( max_size, 0, NULL, 0, &writer->output_heap, NULL );
215 if (hr != S_OK)
217 free_writer( writer );
218 return hr;
221 hr = write_init_state( writer );
222 if (hr != S_OK)
224 free_writer( writer );
225 return hr;
228 *handle = (WS_XML_WRITER *)writer;
229 return S_OK;
232 /**************************************************************************
233 * WsFreeWriter [webservices.@]
235 void WINAPI WsFreeWriter( WS_XML_WRITER *handle )
237 struct writer *writer = (struct writer *)handle;
239 TRACE( "%p\n", handle );
240 free_writer( writer );
243 #define XML_BUFFER_INITIAL_ALLOCATED_SIZE 256
244 static struct xmlbuf *alloc_xmlbuf( WS_HEAP *heap )
246 struct xmlbuf *ret;
248 if (!(ret = ws_alloc( heap, sizeof(*ret) ))) return NULL;
249 if (!(ret->ptr = ws_alloc( heap, XML_BUFFER_INITIAL_ALLOCATED_SIZE )))
251 ws_free( heap, ret );
252 return NULL;
254 ret->heap = heap;
255 ret->size_allocated = XML_BUFFER_INITIAL_ALLOCATED_SIZE;
256 ret->size = 0;
257 return ret;
260 static void free_xmlbuf( struct xmlbuf *xmlbuf )
262 if (!xmlbuf) return;
263 ws_free( xmlbuf->heap, xmlbuf->ptr );
264 ws_free( xmlbuf->heap, xmlbuf );
267 /**************************************************************************
268 * WsCreateXmlBuffer [webservices.@]
270 HRESULT WINAPI WsCreateXmlBuffer( WS_HEAP *heap, const WS_XML_BUFFER_PROPERTY *properties,
271 ULONG count, WS_XML_BUFFER **handle, WS_ERROR *error )
273 struct xmlbuf *xmlbuf;
275 if (!heap || !handle) return E_INVALIDARG;
276 if (count) FIXME( "properties not implemented\n" );
278 if (!(xmlbuf = alloc_xmlbuf( heap ))) return E_OUTOFMEMORY;
280 *handle = (WS_XML_BUFFER *)xmlbuf;
281 return S_OK;
284 /**************************************************************************
285 * WsGetWriterProperty [webservices.@]
287 HRESULT WINAPI WsGetWriterProperty( WS_XML_WRITER *handle, WS_XML_WRITER_PROPERTY_ID id,
288 void *buf, ULONG size, WS_ERROR *error )
290 struct writer *writer = (struct writer *)handle;
292 TRACE( "%p %u %p %u %p\n", handle, id, buf, size, error );
293 if (error) FIXME( "ignoring error parameter\n" );
295 if (!writer->output_type) return WS_E_INVALID_OPERATION;
297 switch (id)
299 case WS_XML_WRITER_PROPERTY_BYTES:
301 WS_BYTES *bytes = buf;
302 if (size != sizeof(*bytes)) return E_INVALIDARG;
303 bytes->bytes = writer->output_buf->ptr;
304 bytes->length = writer->output_buf->size;
305 return S_OK;
307 default:
308 return get_writer_prop( writer, id, buf, size );
312 static void set_output_buffer( struct writer *writer, struct xmlbuf *xmlbuf )
314 /* free current buffer if it's ours */
315 if (writer->output_buf && writer->output_buf->heap == writer->output_heap)
317 free_xmlbuf( writer->output_buf );
319 writer->output_buf = xmlbuf;
320 writer->output_type = WS_XML_WRITER_OUTPUT_TYPE_BUFFER;
321 writer->write_bufptr = xmlbuf->ptr;
322 writer->write_pos = 0;
325 /**************************************************************************
326 * WsSetOutput [webservices.@]
328 HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING *encoding,
329 const WS_XML_WRITER_OUTPUT *output, const WS_XML_WRITER_PROPERTY *properties,
330 ULONG count, WS_ERROR *error )
332 struct writer *writer = (struct writer *)handle;
333 struct node *node;
334 HRESULT hr;
335 ULONG i;
337 TRACE( "%p %p %p %p %u %p\n", handle, encoding, output, properties, count, error );
338 if (error) FIXME( "ignoring error parameter\n" );
340 if (!writer) return E_INVALIDARG;
342 for (i = 0; i < count; i++)
344 hr = set_writer_prop( writer, properties[i].id, properties[i].value, properties[i].valueSize );
345 if (hr != S_OK) return hr;
348 if ((hr = write_init_state( writer )) != S_OK) return hr;
350 switch (encoding->encodingType)
352 case WS_XML_WRITER_ENCODING_TYPE_TEXT:
354 WS_XML_WRITER_TEXT_ENCODING *text = (WS_XML_WRITER_TEXT_ENCODING *)encoding;
355 if (text->charSet != WS_CHARSET_UTF8)
357 FIXME( "charset %u not supported\n", text->charSet );
358 return E_NOTIMPL;
360 break;
362 default:
363 FIXME( "encoding type %u not supported\n", encoding->encodingType );
364 return E_NOTIMPL;
366 switch (output->outputType)
368 case WS_XML_WRITER_OUTPUT_TYPE_BUFFER:
370 struct xmlbuf *xmlbuf;
372 if (!(xmlbuf = alloc_xmlbuf( writer->output_heap ))) return E_OUTOFMEMORY;
373 set_output_buffer( writer, xmlbuf );
374 break;
376 default:
377 FIXME( "output type %u not supported\n", output->outputType );
378 return E_NOTIMPL;
381 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) return E_OUTOFMEMORY;
382 write_insert_bof( writer, node );
383 return S_OK;
386 /**************************************************************************
387 * WsSetOutputToBuffer [webservices.@]
389 HRESULT WINAPI WsSetOutputToBuffer( WS_XML_WRITER *handle, WS_XML_BUFFER *buffer,
390 const WS_XML_WRITER_PROPERTY *properties, ULONG count,
391 WS_ERROR *error )
393 struct writer *writer = (struct writer *)handle;
394 struct xmlbuf *xmlbuf = (struct xmlbuf *)buffer;
395 struct node *node;
396 HRESULT hr;
397 ULONG i;
399 TRACE( "%p %p %p %u %p\n", handle, buffer, properties, count, error );
400 if (error) FIXME( "ignoring error parameter\n" );
402 if (!writer || !xmlbuf) return E_INVALIDARG;
404 for (i = 0; i < count; i++)
406 hr = set_writer_prop( writer, properties[i].id, properties[i].value, properties[i].valueSize );
407 if (hr != S_OK) return hr;
410 if ((hr = write_init_state( writer )) != S_OK) return hr;
411 set_output_buffer( writer, xmlbuf );
413 if (!(node = alloc_node( WS_XML_NODE_TYPE_BOF ))) return E_OUTOFMEMORY;
414 write_insert_bof( writer, node );
415 return S_OK;
418 static HRESULT write_grow_buffer( struct writer *writer, ULONG size )
420 struct xmlbuf *buf = writer->output_buf;
421 SIZE_T new_size;
422 void *tmp;
424 if (buf->size_allocated >= writer->write_pos + size)
426 buf->size = writer->write_pos + size;
427 return S_OK;
429 new_size = max( buf->size_allocated * 2, writer->write_pos + size );
430 if (!(tmp = ws_realloc( buf->heap, buf->ptr, new_size ))) return E_OUTOFMEMORY;
431 writer->write_bufptr = buf->ptr = tmp;
432 buf->size_allocated = new_size;
433 buf->size = writer->write_pos + size;
434 return S_OK;
437 static inline void write_char( struct writer *writer, char ch )
439 writer->write_bufptr[writer->write_pos++] = ch;
442 static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG len )
444 memcpy( writer->write_bufptr + writer->write_pos, bytes, len );
445 writer->write_pos += len;
448 static HRESULT write_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
450 WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)attr->value;
451 ULONG size;
452 HRESULT hr;
454 /* ' prefix:attr="value"' */
456 size = attr->localName->length + 4 /* ' =""' */;
457 if (attr->prefix) size += attr->prefix->length + 1 /* ':' */;
458 if (text) size += text->value.length;
459 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
461 write_char( writer, ' ' );
462 if (attr->prefix)
464 write_bytes( writer, attr->prefix->bytes, attr->prefix->length );
465 write_char( writer, ':' );
467 write_bytes( writer, attr->localName->bytes, attr->localName->length );
468 write_char( writer, '=' );
469 if (attr->singleQuote) write_char( writer, '\'' );
470 else write_char( writer, '"' );
471 if (text) write_bytes( writer, text->value.bytes, text->value.length );
472 if (attr->singleQuote) write_char( writer, '\'' );
473 else write_char( writer, '"' );
475 /* FIXME: ignoring namespace */
476 return S_OK;
479 static HRESULT write_startelement( struct writer *writer )
481 WS_XML_ELEMENT_NODE *elem = (WS_XML_ELEMENT_NODE *)writer->current;
482 ULONG size, i;
483 HRESULT hr;
485 /* '<prefix:localname prefix:attr="value"... xmlns:prefix="ns"' */
487 size = elem->localName->length + 1 /* '<' */;
488 if (elem->prefix) size += elem->prefix->length + 1 /* ':' */;
489 if (elem->ns->length)
491 size += strlen(" xmlns") + elem->ns->length + 3 /* '=""' */;
492 if (elem->prefix) size += elem->prefix->length + 1 /* ':' */;
494 if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
496 write_char( writer, '<' );
497 if (elem->prefix)
499 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
500 write_char( writer, ':' );
502 write_bytes( writer, elem->localName->bytes, elem->localName->length );
503 for (i = 0; i < elem->attributeCount; i++)
505 if ((hr = write_attribute( writer, elem->attributes[i] )) != S_OK) return hr;
507 if (elem->ns->length)
509 write_bytes( writer, (const BYTE *)" xmlns", 6 );
510 if (elem->prefix)
512 write_char( writer, ':' );
513 write_bytes( writer, elem->prefix->bytes, elem->prefix->length );
515 write_char( writer, '=' );
516 write_char( writer, '"' );
517 write_bytes( writer, elem->ns->bytes, elem->ns->length );
518 write_char( writer, '"' );
520 return S_OK;
523 /**************************************************************************
524 * WsWriteStartElement [webservices.@]
526 HRESULT WINAPI WsWriteStartElement( WS_XML_WRITER *handle, const WS_XML_STRING *prefix,
527 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
528 WS_ERROR *error )
530 struct writer *writer = (struct writer *)handle;
531 struct node *node;
532 WS_XML_ELEMENT_NODE *elem;
533 HRESULT hr = E_OUTOFMEMORY;
535 TRACE( "%p %s %s %s %p\n", handle, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
536 debugstr_xmlstr(ns), error );
537 if (error) FIXME( "ignoring error parameter\n" );
539 if (!writer || !localname || !ns) return E_INVALIDARG;
541 /* flush current start element */
542 if (writer->state == WRITER_STATE_STARTELEMENT)
544 if ((hr = write_startelement( writer )) != S_OK) return hr;
545 if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
546 write_char( writer, '>' );
549 if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
550 elem = (WS_XML_ELEMENT_NODE *)node;
552 if (prefix && !(elem->prefix = alloc_xml_string( (const char *)prefix->bytes, prefix->length )))
553 goto error;
555 if (!(elem->localName = alloc_xml_string( (const char *)localname->bytes, localname->length )))
556 goto error;
558 if (!(elem->ns = alloc_xml_string( (const char *)ns->bytes, ns->length )))
559 goto error;
561 write_insert_node( writer, node );
562 writer->state = WRITER_STATE_STARTELEMENT;
563 return S_OK;
565 error:
566 free_node( node );
567 return hr;