quartz: Remove unused variables.
[wine] / dlls / xmllite / reader.c
1 /*
2  * IXmlReader implementation
3  *
4  * Copyright 2010 Nikolay Sivov
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "initguid.h"
27 #include "objbase.h"
28 #include "xmllite.h"
29 #include "xmllite_private.h"
30
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(xmllite);
35
36 /* not defined in public headers */
37 DEFINE_GUID(IID_IXmlReaderInput, 0x0b3ccc9b, 0x9214, 0x428b, 0xa2, 0xae, 0xef, 0x3a, 0xa8, 0x71, 0xaf, 0xda);
38
39 typedef enum
40 {
41     XmlEncoding_UTF16,
42     XmlEncoding_UTF8,
43     XmlEncoding_Unknown
44 } xml_encoding;
45
46 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
47 static const WCHAR utf8W[] = {'U','T','F','-','8',0};
48
49 struct xml_encoding_data
50 {
51     const WCHAR *encoding;
52     xml_encoding enc;
53     UINT cp;
54 };
55
56 static const struct xml_encoding_data xml_encoding_map[] = {
57     { utf16W, XmlEncoding_UTF16, ~0 },
58     { utf8W,  XmlEncoding_UTF8,  CP_UTF8 }
59 };
60
61 typedef struct
62 {
63     char *data;
64     unsigned int allocated;
65     unsigned int written;
66 } encoded_buffer;
67
68 typedef struct input_buffer input_buffer;
69
70 typedef struct _xmlreaderinput
71 {
72     IXmlReaderInput IXmlReaderInput_iface;
73     LONG ref;
74     /* reference passed on IXmlReaderInput creation, is kept when input is created */
75     IUnknown *input;
76     IMalloc *imalloc;
77     xml_encoding encoding;
78     BOOL hint;
79     WCHAR *baseuri;
80     /* stream reference set after SetInput() call from reader,
81        stored as sequential stream, cause currently
82        optimizations possible with IStream aren't implemented */
83     ISequentialStream *stream;
84     input_buffer *buffer;
85 } xmlreaderinput;
86
87 typedef struct _xmlreader
88 {
89     IXmlReader IXmlReader_iface;
90     LONG ref;
91     xmlreaderinput *input;
92     IMalloc *imalloc;
93     XmlReadState state;
94     XmlNodeType nodetype;
95     DtdProcessing dtdmode;
96     UINT line, pos;           /* reader position in XML stream */
97 } xmlreader;
98
99 struct input_buffer
100 {
101     encoded_buffer utf16;
102     encoded_buffer encoded;
103     UINT code_page;
104     xmlreaderinput *input;
105 };
106
107 static inline xmlreader *impl_from_IXmlReader(IXmlReader *iface)
108 {
109     return CONTAINING_RECORD(iface, xmlreader, IXmlReader_iface);
110 }
111
112 static inline xmlreaderinput *impl_from_IXmlReaderInput(IXmlReaderInput *iface)
113 {
114     return CONTAINING_RECORD(iface, xmlreaderinput, IXmlReaderInput_iface);
115 }
116
117 static inline void *m_alloc(IMalloc *imalloc, size_t len)
118 {
119     if (imalloc)
120         return IMalloc_Alloc(imalloc, len);
121     else
122         return heap_alloc(len);
123 }
124
125 static inline void *m_realloc(IMalloc *imalloc, void *mem, size_t len)
126 {
127     if (imalloc)
128         return IMalloc_Realloc(imalloc, mem, len);
129     else
130         return heap_realloc(mem, len);
131 }
132
133 static inline void m_free(IMalloc *imalloc, void *mem)
134 {
135     if (imalloc)
136         IMalloc_Free(imalloc, mem);
137     else
138         heap_free(mem);
139 }
140
141 /* reader memory allocation functions */
142 static inline void *reader_alloc(xmlreader *reader, size_t len)
143 {
144     return m_alloc(reader->imalloc, len);
145 }
146
147 static inline void reader_free(xmlreader *reader, void *mem)
148 {
149     return m_free(reader->imalloc, mem);
150 }
151
152 /* reader input memory allocation functions */
153 static inline void *readerinput_alloc(xmlreaderinput *input, size_t len)
154 {
155     return m_alloc(input->imalloc, len);
156 }
157
158 static inline void *readerinput_realloc(xmlreaderinput *input, void *mem, size_t len)
159 {
160     return m_realloc(input->imalloc, mem, len);
161 }
162
163 static inline void readerinput_free(xmlreaderinput *input, void *mem)
164 {
165     return m_free(input->imalloc, mem);
166 }
167
168 static inline WCHAR *readerinput_strdupW(xmlreaderinput *input, const WCHAR *str)
169 {
170     LPWSTR ret = NULL;
171
172     if(str) {
173         DWORD size;
174
175         size = (strlenW(str)+1)*sizeof(WCHAR);
176         ret = readerinput_alloc(input, size);
177         if (ret) memcpy(ret, str, size);
178     }
179
180     return ret;
181 }
182
183 static HRESULT init_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
184 {
185     const int initial_len = 0x2000;
186     buffer->data = readerinput_alloc(input, initial_len);
187     if (!buffer->data) return E_OUTOFMEMORY;
188
189     memset(buffer->data, 0, 4);
190     buffer->allocated = initial_len;
191     buffer->written = 0;
192
193     return S_OK;
194 }
195
196 static void free_encoded_buffer(xmlreaderinput *input, encoded_buffer *buffer)
197 {
198     readerinput_free(input, buffer->data);
199 }
200
201 static HRESULT get_code_page(xml_encoding encoding, xmlreaderinput *input)
202 {
203     const struct xml_encoding_data *data;
204
205     if (encoding == XmlEncoding_Unknown)
206     {
207         FIXME("unsupported encoding %d\n", encoding);
208         return E_NOTIMPL;
209     }
210
211     data = &xml_encoding_map[encoding];
212     input->buffer->code_page = data->cp;
213
214     return S_OK;
215 }
216
217 static xml_encoding parse_encoding_name(const WCHAR *encoding)
218 {
219     int min, max, n, c;
220
221     if (!encoding) return XmlEncoding_Unknown;
222
223     min = 0;
224     max = sizeof(xml_encoding_map)/sizeof(struct xml_encoding_data) - 1;
225
226     while (min <= max)
227     {
228         n = (min+max)/2;
229
230         c = strcmpiW(xml_encoding_map[n].encoding, encoding);
231         if (!c)
232             return xml_encoding_map[n].enc;
233
234         if (c > 0)
235             max = n-1;
236         else
237             min = n+1;
238     }
239
240     return XmlEncoding_Unknown;
241 }
242
243 static HRESULT alloc_input_buffer(xmlreaderinput *input)
244 {
245     input_buffer *buffer;
246     HRESULT hr;
247
248     input->buffer = NULL;
249
250     buffer = readerinput_alloc(input, sizeof(*buffer));
251     if (!buffer) return E_OUTOFMEMORY;
252
253     buffer->input = input;
254     buffer->code_page = ~0; /* code page is unknown at this point */
255     hr = init_encoded_buffer(input, &buffer->utf16);
256     if (hr != S_OK) {
257         readerinput_free(input, buffer);
258         return hr;
259     }
260
261     hr = init_encoded_buffer(input, &buffer->encoded);
262     if (hr != S_OK) {
263         free_encoded_buffer(input, &buffer->utf16);
264         readerinput_free(input, buffer);
265         return hr;
266     }
267
268     input->buffer = buffer;
269     return S_OK;
270 }
271
272 static void free_input_buffer(input_buffer *buffer)
273 {
274     free_encoded_buffer(buffer->input, &buffer->encoded);
275     free_encoded_buffer(buffer->input, &buffer->utf16);
276     readerinput_free(buffer->input, buffer);
277 }
278
279 static void readerinput_release_stream(xmlreaderinput *readerinput)
280 {
281     if (readerinput->stream) {
282         ISequentialStream_Release(readerinput->stream);
283         readerinput->stream = NULL;
284     }
285 }
286
287 /* Queries already stored interface for IStream/ISequentialStream.
288    Interface supplied on creation will be overwritten */
289 static HRESULT readerinput_query_for_stream(xmlreaderinput *readerinput)
290 {
291     HRESULT hr;
292
293     readerinput_release_stream(readerinput);
294     hr = IUnknown_QueryInterface(readerinput->input, &IID_IStream, (void**)&readerinput->stream);
295     if (hr != S_OK)
296         hr = IUnknown_QueryInterface(readerinput->input, &IID_ISequentialStream, (void**)&readerinput->stream);
297
298     return hr;
299 }
300
301 /* reads a chunk to raw buffer */
302 static HRESULT readerinput_growraw(xmlreaderinput *readerinput)
303 {
304     encoded_buffer *buffer = &readerinput->buffer->encoded;
305     ULONG len = buffer->allocated - buffer->written, read;
306     HRESULT hr;
307
308     /* always try to get aligned to 4 bytes, so the only case we can get partialy read characters is
309        variable width encodings like UTF-8 */
310     len = (len + 3) & ~3;
311     /* try to use allocated space or grow */
312     if (buffer->allocated - buffer->written < len)
313     {
314         buffer->allocated *= 2;
315         buffer->data = readerinput_realloc(readerinput, buffer->data, buffer->allocated);
316         len = buffer->allocated - buffer->written;
317     }
318
319     hr = ISequentialStream_Read(readerinput->stream, buffer->data + buffer->written, len, &read);
320     if (FAILED(hr)) return hr;
321     TRACE("requested %d, read %d, ret 0x%08x\n", len, read, hr);
322     buffer->written += read;
323
324     return hr;
325 }
326
327 static xml_encoding readerinput_detectencoding(xmlreaderinput *readerinput)
328 {
329     encoded_buffer *buffer = &readerinput->buffer->encoded;
330
331     /* try start symbols if we have enough data to do that, input buffer should contain
332        first chunk already */
333     if (buffer->written >= 4)
334     {
335         static char startA[] = {'<','?','x','m'};
336         static WCHAR startW[] = {'<','?'};
337
338         if (!memcmp(buffer->data, startA, sizeof(startA))) return XmlEncoding_UTF8;
339         if (!memcmp(buffer->data, startW, sizeof(startW))) return XmlEncoding_UTF16;
340     }
341
342     /* try with BOM now */
343     if (buffer->written >= 3)
344     {
345         static char utf8bom[] = {0xef,0xbb,0xbf};
346         static char utf16lebom[] = {0xff,0xfe};
347         if (!memcmp(buffer->data, utf8bom, sizeof(utf8bom))) return XmlEncoding_UTF8;
348         if (!memcmp(buffer->data, utf16lebom, sizeof(utf16lebom))) return XmlEncoding_UTF16;
349     }
350
351     return XmlEncoding_Unknown;
352 }
353
354 static HRESULT WINAPI xmlreader_QueryInterface(IXmlReader *iface, REFIID riid, void** ppvObject)
355 {
356     xmlreader *This = impl_from_IXmlReader(iface);
357
358     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
359
360     if (IsEqualGUID(riid, &IID_IUnknown) ||
361         IsEqualGUID(riid, &IID_IXmlReader))
362     {
363         *ppvObject = iface;
364     }
365     else
366     {
367         FIXME("interface %s not implemented\n", debugstr_guid(riid));
368         return E_NOINTERFACE;
369     }
370
371     IXmlReader_AddRef(iface);
372
373     return S_OK;
374 }
375
376 static ULONG WINAPI xmlreader_AddRef(IXmlReader *iface)
377 {
378     xmlreader *This = impl_from_IXmlReader(iface);
379     ULONG ref = InterlockedIncrement(&This->ref);
380     TRACE("(%p)->(%d)\n", This, ref);
381     return ref;
382 }
383
384 static ULONG WINAPI xmlreader_Release(IXmlReader *iface)
385 {
386     xmlreader *This = impl_from_IXmlReader(iface);
387     LONG ref = InterlockedDecrement(&This->ref);
388
389     TRACE("(%p)->(%d)\n", This, ref);
390
391     if (ref == 0)
392     {
393         IMalloc *imalloc = This->imalloc;
394         if (This->input) IUnknown_Release(&This->input->IXmlReaderInput_iface);
395         reader_free(This, This);
396         if (imalloc) IMalloc_Release(imalloc);
397     }
398
399     return ref;
400 }
401
402 static HRESULT WINAPI xmlreader_SetInput(IXmlReader* iface, IUnknown *input)
403 {
404     xmlreader *This = impl_from_IXmlReader(iface);
405     HRESULT hr;
406
407     TRACE("(%p %p)\n", This, input);
408
409     if (This->input)
410     {
411         readerinput_release_stream(This->input);
412         IUnknown_Release(&This->input->IXmlReaderInput_iface);
413         This->input = NULL;
414     }
415
416     This->line = This->pos = 0;
417
418     /* just reset current input */
419     if (!input)
420     {
421         This->state = XmlReadState_Initial;
422         return S_OK;
423     }
424
425     /* now try IXmlReaderInput, ISequentialStream, IStream */
426     hr = IUnknown_QueryInterface(input, &IID_IXmlReaderInput, (void**)&This->input);
427     if (hr != S_OK)
428     {
429         IXmlReaderInput *readerinput;
430
431         /* create IXmlReaderInput basing on supplied interface */
432         hr = CreateXmlReaderInputWithEncodingName(input,
433                                          NULL, NULL, FALSE, NULL, &readerinput);
434         if (hr != S_OK) return hr;
435         This->input = impl_from_IXmlReaderInput(readerinput);
436     }
437
438     /* set stream for supplied IXmlReaderInput */
439     hr = readerinput_query_for_stream(This->input);
440     if (hr == S_OK)
441         This->state = XmlReadState_Initial;
442
443     return hr;
444 }
445
446 static HRESULT WINAPI xmlreader_GetProperty(IXmlReader* iface, UINT property, LONG_PTR *value)
447 {
448     xmlreader *This = impl_from_IXmlReader(iface);
449
450     TRACE("(%p %u %p)\n", This, property, value);
451
452     if (!value) return E_INVALIDARG;
453
454     switch (property)
455     {
456         case XmlReaderProperty_DtdProcessing:
457             *value = This->dtdmode;
458             break;
459         case XmlReaderProperty_ReadState:
460             *value = This->state;
461             break;
462         default:
463             FIXME("Unimplemented property (%u)\n", property);
464             return E_NOTIMPL;
465     }
466
467     return S_OK;
468 }
469
470 static HRESULT WINAPI xmlreader_SetProperty(IXmlReader* iface, UINT property, LONG_PTR value)
471 {
472     xmlreader *This = impl_from_IXmlReader(iface);
473
474     TRACE("(%p %u %lu)\n", iface, property, value);
475
476     switch (property)
477     {
478         case XmlReaderProperty_DtdProcessing:
479             if (value < 0 || value > _DtdProcessing_Last) return E_INVALIDARG;
480             This->dtdmode = value;
481             break;
482         default:
483             FIXME("Unimplemented property (%u)\n", property);
484             return E_NOTIMPL;
485     }
486
487     return S_OK;
488 }
489
490 static HRESULT WINAPI xmlreader_Read(IXmlReader* iface, XmlNodeType *node_type)
491 {
492     xmlreader *This = impl_from_IXmlReader(iface);
493
494     FIXME("(%p)->(%p): stub\n", This, node_type);
495
496     if (This->state == XmlReadState_Closed) return S_FALSE;
497
498     /* if it's a first call for a new input we need to detect stream encoding */
499     if (This->state == XmlReadState_Initial)
500     {
501         xml_encoding enc;
502         HRESULT hr;
503
504         hr = readerinput_growraw(This->input);
505         if (FAILED(hr)) return hr;
506
507         /* try to detect encoding by BOM or data and set input code page */
508         enc = readerinput_detectencoding(This->input);
509         TRACE("detected encoding %d\n", enc);
510         get_code_page(enc, This->input);
511     }
512
513     return E_NOTIMPL;
514 }
515
516 static HRESULT WINAPI xmlreader_GetNodeType(IXmlReader* iface, XmlNodeType *node_type)
517 {
518     xmlreader *This = impl_from_IXmlReader(iface);
519     TRACE("(%p)->(%p)\n", This, node_type);
520     *node_type = This->nodetype;
521     return This->state == XmlReadState_Closed ? S_FALSE : S_OK;
522 }
523
524 static HRESULT WINAPI xmlreader_MoveToFirstAttribute(IXmlReader* iface)
525 {
526     FIXME("(%p): stub\n", iface);
527     return E_NOTIMPL;
528 }
529
530 static HRESULT WINAPI xmlreader_MoveToNextAttribute(IXmlReader* iface)
531 {
532     FIXME("(%p): stub\n", iface);
533     return E_NOTIMPL;
534 }
535
536 static HRESULT WINAPI xmlreader_MoveToAttributeByName(IXmlReader* iface,
537                                                       LPCWSTR local_name,
538                                                       LPCWSTR namespaceUri)
539 {
540     FIXME("(%p %p %p): stub\n", iface, local_name, namespaceUri);
541     return E_NOTIMPL;
542 }
543
544 static HRESULT WINAPI xmlreader_MoveToElement(IXmlReader* iface)
545 {
546     FIXME("(%p): stub\n", iface);
547     return E_NOTIMPL;
548 }
549
550 static HRESULT WINAPI xmlreader_GetQualifiedName(IXmlReader* iface, LPCWSTR *qualifiedName,
551                                                  UINT *qualifiedName_length)
552 {
553     FIXME("(%p %p %p): stub\n", iface, qualifiedName, qualifiedName_length);
554     return E_NOTIMPL;
555 }
556
557 static HRESULT WINAPI xmlreader_GetNamespaceUri(IXmlReader* iface,
558                                                 LPCWSTR *namespaceUri,
559                                                 UINT *namespaceUri_length)
560 {
561     FIXME("(%p %p %p): stub\n", iface, namespaceUri, namespaceUri_length);
562     return E_NOTIMPL;
563 }
564
565 static HRESULT WINAPI xmlreader_GetLocalName(IXmlReader* iface,
566                                              LPCWSTR *local_name,
567                                              UINT *local_name_length)
568 {
569     FIXME("(%p %p %p): stub\n", iface, local_name, local_name_length);
570     return E_NOTIMPL;
571 }
572
573 static HRESULT WINAPI xmlreader_GetPrefix(IXmlReader* iface,
574                                           LPCWSTR *prefix,
575                                           UINT *prefix_length)
576 {
577     FIXME("(%p %p %p): stub\n", iface, prefix, prefix_length);
578     return E_NOTIMPL;
579 }
580
581 static HRESULT WINAPI xmlreader_GetValue(IXmlReader* iface,
582                                          LPCWSTR *value,
583                                          UINT *value_length)
584 {
585     FIXME("(%p %p %p): stub\n", iface, value, value_length);
586     return E_NOTIMPL;
587 }
588
589 static HRESULT WINAPI xmlreader_ReadValueChunk(IXmlReader* iface,
590                                                WCHAR *buffer,
591                                                UINT   chunk_size,
592                                                UINT  *read)
593 {
594     FIXME("(%p %p %u %p): stub\n", iface, buffer, chunk_size, read);
595     return E_NOTIMPL;
596 }
597
598 static HRESULT WINAPI xmlreader_GetBaseUri(IXmlReader* iface,
599                                            LPCWSTR *baseUri,
600                                            UINT *baseUri_length)
601 {
602     FIXME("(%p %p %p): stub\n", iface, baseUri, baseUri_length);
603     return E_NOTIMPL;
604 }
605
606 static BOOL WINAPI xmlreader_IsDefault(IXmlReader* iface)
607 {
608     FIXME("(%p): stub\n", iface);
609     return E_NOTIMPL;
610 }
611
612 static BOOL WINAPI xmlreader_IsEmptyElement(IXmlReader* iface)
613 {
614     FIXME("(%p): stub\n", iface);
615     return E_NOTIMPL;
616 }
617
618 static HRESULT WINAPI xmlreader_GetLineNumber(IXmlReader* iface, UINT *lineNumber)
619 {
620     xmlreader *This = impl_from_IXmlReader(iface);
621
622     TRACE("(%p %p)\n", This, lineNumber);
623
624     if (!lineNumber) return E_INVALIDARG;
625
626     *lineNumber = This->line;
627
628     return S_OK;
629 }
630
631 static HRESULT WINAPI xmlreader_GetLinePosition(IXmlReader* iface, UINT *linePosition)
632 {
633     xmlreader *This = impl_from_IXmlReader(iface);
634
635     TRACE("(%p %p)\n", This, linePosition);
636
637     if (!linePosition) return E_INVALIDARG;
638
639     *linePosition = This->pos;
640
641     return S_OK;
642 }
643
644 static HRESULT WINAPI xmlreader_GetAttributeCount(IXmlReader* iface, UINT *attributeCount)
645 {
646     FIXME("(%p %p): stub\n", iface, attributeCount);
647     return E_NOTIMPL;
648 }
649
650 static HRESULT WINAPI xmlreader_GetDepth(IXmlReader* iface, UINT *depth)
651 {
652     FIXME("(%p %p): stub\n", iface, depth);
653     return E_NOTIMPL;
654 }
655
656 static BOOL WINAPI xmlreader_IsEOF(IXmlReader* iface)
657 {
658     FIXME("(%p): stub\n", iface);
659     return E_NOTIMPL;
660 }
661
662 static const struct IXmlReaderVtbl xmlreader_vtbl =
663 {
664     xmlreader_QueryInterface,
665     xmlreader_AddRef,
666     xmlreader_Release,
667     xmlreader_SetInput,
668     xmlreader_GetProperty,
669     xmlreader_SetProperty,
670     xmlreader_Read,
671     xmlreader_GetNodeType,
672     xmlreader_MoveToFirstAttribute,
673     xmlreader_MoveToNextAttribute,
674     xmlreader_MoveToAttributeByName,
675     xmlreader_MoveToElement,
676     xmlreader_GetQualifiedName,
677     xmlreader_GetNamespaceUri,
678     xmlreader_GetLocalName,
679     xmlreader_GetPrefix,
680     xmlreader_GetValue,
681     xmlreader_ReadValueChunk,
682     xmlreader_GetBaseUri,
683     xmlreader_IsDefault,
684     xmlreader_IsEmptyElement,
685     xmlreader_GetLineNumber,
686     xmlreader_GetLinePosition,
687     xmlreader_GetAttributeCount,
688     xmlreader_GetDepth,
689     xmlreader_IsEOF
690 };
691
692 /** IXmlReaderInput **/
693 static HRESULT WINAPI xmlreaderinput_QueryInterface(IXmlReaderInput *iface, REFIID riid, void** ppvObject)
694 {
695     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
696
697     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
698
699     if (IsEqualGUID(riid, &IID_IXmlReaderInput) ||
700         IsEqualGUID(riid, &IID_IUnknown))
701     {
702         *ppvObject = iface;
703     }
704     else
705     {
706         WARN("interface %s not implemented\n", debugstr_guid(riid));
707         return E_NOINTERFACE;
708     }
709
710     IUnknown_AddRef(iface);
711
712     return S_OK;
713 }
714
715 static ULONG WINAPI xmlreaderinput_AddRef(IXmlReaderInput *iface)
716 {
717     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
718     ULONG ref = InterlockedIncrement(&This->ref);
719     TRACE("(%p)->(%d)\n", This, ref);
720     return ref;
721 }
722
723 static ULONG WINAPI xmlreaderinput_Release(IXmlReaderInput *iface)
724 {
725     xmlreaderinput *This = impl_from_IXmlReaderInput(iface);
726     LONG ref = InterlockedDecrement(&This->ref);
727
728     TRACE("(%p)->(%d)\n", This, ref);
729
730     if (ref == 0)
731     {
732         IMalloc *imalloc = This->imalloc;
733         if (This->input) IUnknown_Release(This->input);
734         if (This->stream) ISequentialStream_Release(This->stream);
735         if (This->buffer) free_input_buffer(This->buffer);
736         readerinput_free(This, This->baseuri);
737         readerinput_free(This, This);
738         if (imalloc) IMalloc_Release(imalloc);
739     }
740
741     return ref;
742 }
743
744 static const struct IUnknownVtbl xmlreaderinput_vtbl =
745 {
746     xmlreaderinput_QueryInterface,
747     xmlreaderinput_AddRef,
748     xmlreaderinput_Release
749 };
750
751 HRESULT WINAPI CreateXmlReader(REFIID riid, void **obj, IMalloc *imalloc)
752 {
753     xmlreader *reader;
754
755     TRACE("(%s, %p, %p)\n", wine_dbgstr_guid(riid), obj, imalloc);
756
757     if (!IsEqualGUID(riid, &IID_IXmlReader))
758     {
759         ERR("Unexpected IID requested -> (%s)\n", wine_dbgstr_guid(riid));
760         return E_FAIL;
761     }
762
763     if (imalloc)
764         reader = IMalloc_Alloc(imalloc, sizeof(*reader));
765     else
766         reader = heap_alloc(sizeof(*reader));
767     if(!reader) return E_OUTOFMEMORY;
768
769     reader->IXmlReader_iface.lpVtbl = &xmlreader_vtbl;
770     reader->ref = 1;
771     reader->input = NULL;
772     reader->state = XmlReadState_Closed;
773     reader->dtdmode = DtdProcessing_Prohibit;
774     reader->line  = reader->pos = 0;
775     reader->imalloc = imalloc;
776     if (imalloc) IMalloc_AddRef(imalloc);
777     reader->nodetype = XmlNodeType_None;
778
779     *obj = &reader->IXmlReader_iface;
780
781     TRACE("returning iface %p\n", *obj);
782
783     return S_OK;
784 }
785
786 HRESULT WINAPI CreateXmlReaderInputWithEncodingName(IUnknown *stream,
787                                                     IMalloc *imalloc,
788                                                     LPCWSTR encoding,
789                                                     BOOL hint,
790                                                     LPCWSTR base_uri,
791                                                     IXmlReaderInput **ppInput)
792 {
793     xmlreaderinput *readerinput;
794     HRESULT hr;
795
796     TRACE("%p %p %s %d %s %p\n", stream, imalloc, wine_dbgstr_w(encoding),
797                                        hint, wine_dbgstr_w(base_uri), ppInput);
798
799     if (!stream || !ppInput) return E_INVALIDARG;
800
801     if (imalloc)
802         readerinput = IMalloc_Alloc(imalloc, sizeof(*readerinput));
803     else
804         readerinput = heap_alloc(sizeof(*readerinput));
805     if(!readerinput) return E_OUTOFMEMORY;
806
807     readerinput->IXmlReaderInput_iface.lpVtbl = &xmlreaderinput_vtbl;
808     readerinput->ref = 1;
809     readerinput->imalloc = imalloc;
810     readerinput->stream = NULL;
811     if (imalloc) IMalloc_AddRef(imalloc);
812     readerinput->encoding = parse_encoding_name(encoding);
813     readerinput->hint = hint;
814     readerinput->baseuri = readerinput_strdupW(readerinput, base_uri);
815
816     hr = alloc_input_buffer(readerinput);
817     if (hr != S_OK)
818     {
819         readerinput_free(readerinput, readerinput);
820         return hr;
821     }
822     IUnknown_QueryInterface(stream, &IID_IUnknown, (void**)&readerinput->input);
823
824     *ppInput = &readerinput->IXmlReaderInput_iface;
825
826     TRACE("returning iface %p\n", *ppInput);
827
828     return S_OK;
829 }