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
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
);
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 */
62 WRITER_STATE_STARTELEMENT
,
63 WRITER_STATE_STARTENDELEMENT
,
64 WRITER_STATE_STARTATTRIBUTE
,
65 WRITER_STATE_ENDSTARTELEMENT
,
66 WRITER_STATE_ENDELEMENT
73 enum writer_state state
;
76 WS_XML_WRITER_OUTPUT_TYPE output_type
;
77 struct xmlbuf
*output_buf
;
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]);
87 ULONG i
, size
= sizeof(*ret
) + count
* sizeof(WS_XML_WRITER_PROPERTY
);
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
;
104 static HRESULT
set_writer_prop( struct writer
*writer
, WS_XML_WRITER_PROPERTY_ID id
, const void *value
,
107 if (id
>= writer
->prop_count
|| size
!= writer_props
[id
].size
|| writer_props
[id
].readonly
)
110 memcpy( writer
->prop
[id
].value
, value
, size
);
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
)
119 memcpy( buf
, writer
->prop
[id
].value
, writer
->prop
[id
].valueSize
);
123 static void free_writer( struct writer
*writer
)
125 destroy_nodes( writer
->root
);
126 WsFreeHeap( writer
->output_heap
);
130 static void write_insert_eof( struct writer
*writer
, struct node
*eof
)
132 if (!writer
->root
) writer
->root
= eof
;
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
)
164 destroy_nodes( writer
->root
);
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
;
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
;
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
);
202 free_writer( writer
);
207 hr
= get_writer_prop( writer
, WS_XML_WRITER_PROPERTY_BUFFER_MAX_SIZE
, &max_size
, sizeof(max_size
) );
210 free_writer( writer
);
214 hr
= WsCreateHeap( max_size
, 0, NULL
, 0, &writer
->output_heap
, NULL
);
217 free_writer( writer
);
221 hr
= write_init_state( writer
);
224 free_writer( writer
);
228 *handle
= (WS_XML_WRITER
*)writer
;
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
)
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
);
255 ret
->size_allocated
= XML_BUFFER_INITIAL_ALLOCATED_SIZE
;
260 static void free_xmlbuf( struct xmlbuf
*xmlbuf
)
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
;
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
;
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
;
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
;
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
);
363 FIXME( "encoding type %u not supported\n", encoding
->encodingType
);
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
);
377 FIXME( "output type %u not supported\n", output
->outputType
);
381 if (!(node
= alloc_node( WS_XML_NODE_TYPE_BOF
))) return E_OUTOFMEMORY
;
382 write_insert_bof( writer
, node
);
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
,
393 struct writer
*writer
= (struct writer
*)handle
;
394 struct xmlbuf
*xmlbuf
= (struct xmlbuf
*)buffer
;
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
);
418 static HRESULT
write_grow_buffer( struct writer
*writer
, ULONG size
)
420 struct xmlbuf
*buf
= writer
->output_buf
;
424 if (buf
->size_allocated
>= writer
->write_pos
+ size
)
426 buf
->size
= writer
->write_pos
+ size
;
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
;
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
;
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
, ' ' );
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 */
479 static HRESULT
write_startelement( struct writer
*writer
)
481 WS_XML_ELEMENT_NODE
*elem
= (WS_XML_ELEMENT_NODE
*)writer
->current
;
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
, '<' );
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 );
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
, '"' );
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
,
530 struct writer
*writer
= (struct writer
*)handle
;
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
)))
555 if (!(elem
->localName
= alloc_xml_string( (const char *)localname
->bytes
, localname
->length
)))
558 if (!(elem
->ns
= alloc_xml_string( (const char *)ns
->bytes
, ns
->length
)))
561 write_insert_node( writer
, node
);
562 writer
->state
= WRITER_STATE_STARTELEMENT
;