saxreader.c 96.3 KB
Newer Older
1 2 3 4
/*
 *    SAX Reader implementation
 *
 * Copyright 2008 Alistair Leslie-Hughes
5
 * Copyright 2008 Piotr Caban
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */
#define COBJMACROS

#include "config.h"

#include <stdarg.h>
26 27 28 29 30 31 32
#ifdef HAVE_LIBXML2
# include <libxml/parser.h>
# include <libxml/xmlerror.h>
# include <libxml/SAX2.h>
# include <libxml/parserInternals.h>
#endif

33 34 35 36 37
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winnls.h"
#include "ole2.h"
38
#include "msxml6.h"
39 40 41 42 43 44 45 46 47 48 49
#include "wininet.h"
#include "urlmon.h"
#include "winreg.h"
#include "shlwapi.h"

#include "wine/debug.h"

#include "msxml_private.h"

#ifdef HAVE_LIBXML2

50 51
WINE_DEFAULT_DEBUG_CHANNEL(msxml);

52
typedef enum
53
{
54
    FeatureUnknown               = 0,
55 56 57 58 59
    ExhaustiveErrors             = 1 << 1,
    ExternalGeneralEntities      = 1 << 2,
    ExternalParameterEntities    = 1 << 3,
    ForcedResync                 = 1 << 4,
    NamespacePrefixes            = 1 << 5,
60
    Namespaces                   = 1 << 6,
61 62 63 64 65 66 67
    ParameterEntities            = 1 << 7,
    PreserveSystemIndentifiers   = 1 << 8,
    ProhibitDTD                  = 1 << 9,
    SchemaValidation             = 1 << 10,
    ServerHttpRequest            = 1 << 11,
    SuppressValidationfatalError = 1 << 12,
    UseInlineSchema              = 1 << 13,
68 69
    UseSchemaLocation            = 1 << 14,
    LexicalHandlerParEntities    = 1 << 15
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
} saxreader_feature;

/* feature names */
static const WCHAR FeatureExternalGeneralEntitiesW[] = {
    'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/','s','a','x','/',
    'f','e','a','t','u','r','e','s','/','e','x','t','e','r','n','a','l','-','g','e','n','e','r','a','l',
    '-','e','n','t','i','t','i','e','s',0
};

static const WCHAR FeatureExternalParameterEntitiesW[] = {
    'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/','s','a','x','/','f','e','a','t','u','r','e','s',
    '/','e','x','t','e','r','n','a','l','-','p','a','r','a','m','e','t','e','r','-','e','n','t','i','t','i','e','s',0
};

static const WCHAR FeatureLexicalHandlerParEntitiesW[] = {
    'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/','s','a','x','/','f','e','a','t','u','r','e','s',
    '/','l','e','x','i','c','a','l','-','h','a','n','d','l','e','r','/','p','a','r','a','m','e','t','e','r','-','e','n','t','i','t','i','e','s',0
};

static const WCHAR FeatureProhibitDTDW[] = {
    'p','r','o','h','i','b','i','t','-','d','t','d',0
};

static const WCHAR FeatureNamespacesW[] = {
    'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/','s','a','x','/','f','e','a','t','u','r','e','s',
    '/','n','a','m','e','s','p','a','c','e','s',0
};

static const WCHAR FeatureNamespacePrefixesW[] = {
    'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/','s','a','x','/','f','e','a','t','u','r','e','s',
    '/','n','a','m','e','s','p','a','c','e','-','p','r','e','f','i','x','e','s',0
};

struct saxreader_feature_pair
{
    saxreader_feature feature;
    const WCHAR *name;
};

static const struct saxreader_feature_pair saxreader_feature_map[] = {
    { ExternalGeneralEntities, FeatureExternalGeneralEntitiesW },
    { ExternalParameterEntities, FeatureExternalParameterEntitiesW },
    { LexicalHandlerParEntities, FeatureLexicalHandlerParEntitiesW },
    { NamespacePrefixes, FeatureNamespacePrefixesW },
    { Namespaces, FeatureNamespacesW },
    { ProhibitDTD, FeatureProhibitDTDW }
};

static saxreader_feature get_saxreader_feature(const WCHAR *name)
{
    int min, max, n, c;

    min = 0;
    max = sizeof(saxreader_feature_map)/sizeof(struct saxreader_feature_pair) - 1;

    while (min <= max)
    {
        n = (min+max)/2;

        c = strcmpW(saxreader_feature_map[n].name, name);
        if (!c)
            return saxreader_feature_map[n].feature;

        if (c > 0)
            max = n-1;
        else
            min = n+1;
    }

    return FeatureUnknown;
}
141

142 143 144 145 146 147 148
struct bstrpool
{
    BSTR *pool;
    unsigned int index;
    unsigned int len;
};

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
typedef struct
{
    BSTR prefix;
    BSTR uri;
} ns;

typedef struct
{
    struct list entry;
    BSTR prefix;
    BSTR local;
    BSTR qname;
    ns *ns; /* namespaces defined in this particular element */
    int ns_count;
} element_entry;

165 166 167 168 169
enum saxhandler_type
{
    SAXContentHandler = 0,
    SAXDeclHandler,
    SAXDTDHandler,
170
    SAXEntityResolver,
171 172 173 174 175
    SAXErrorHandler,
    SAXLexicalHandler,
    SAXHandler_Last
};

176
struct saxanyhandler_iface
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
{
    IUnknown *handler;
    IUnknown *vbhandler;
};

struct saxcontenthandler_iface
{
    ISAXContentHandler *handler;
    IVBSAXContentHandler *vbhandler;
};

struct saxerrorhandler_iface
{
    ISAXErrorHandler *handler;
    IVBSAXErrorHandler *vbhandler;
};

struct saxlexicalhandler_iface
{
    ISAXLexicalHandler *handler;
    IVBSAXLexicalHandler *vbhandler;
};

200 201 202 203 204 205
struct saxentityresolver_iface
{
    ISAXEntityResolver *handler;
    IVBSAXEntityResolver *vbhandler;
};

206 207 208 209
struct saxhandler_iface
{
    union {
        struct saxcontenthandler_iface content;
210
        struct saxentityresolver_iface entityresolver;
211 212 213 214 215 216
        struct saxerrorhandler_iface error;
        struct saxlexicalhandler_iface lexical;
        struct saxanyhandler_iface anyhandler;
    } u;
};

217
typedef struct
218
{
219
    DispatchEx dispex;
220 221
    IVBSAXXMLReader IVBSAXXMLReader_iface;
    ISAXXMLReader ISAXXMLReader_iface;
222
    LONG ref;
223 224

    struct saxhandler_iface saxhandlers[SAXHandler_Last];
225
    xmlSAXHandler sax;
226
    BOOL isParsing;
227
    struct bstrpool pool;
228
    saxreader_feature features;
229
    BSTR xmldecl_version;
230
    MSXML_VERSION version;
231 232
} saxreader;

233 234
static HRESULT saxreader_put_handler(saxreader *reader, enum saxhandler_type type, void *ptr, BOOL vb)
{
235
    struct saxanyhandler_iface *iface = &reader->saxhandlers[type].u.anyhandler;
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
    IUnknown *unk = (IUnknown*)ptr;

    if (unk)
        IUnknown_AddRef(unk);

    if ((vb && iface->vbhandler) || (!vb && iface->handler))
        IUnknown_Release(vb ? iface->vbhandler : iface->handler);

    if (vb)
        iface->vbhandler = unk;
    else
        iface->handler = unk;

    return S_OK;
}

static HRESULT saxreader_get_handler(const saxreader *reader, enum saxhandler_type type, BOOL vb, void **ret)
{
254
    const struct saxanyhandler_iface *iface = &reader->saxhandlers[type].u.anyhandler;
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272

    if (!ret) return E_POINTER;

    if ((vb && iface->vbhandler) || (!vb && iface->handler))
    {
        if (vb)
            IUnknown_AddRef(iface->vbhandler);
        else
            IUnknown_AddRef(iface->handler);
    }

    *ret = vb ? iface->vbhandler : iface->handler;

    return S_OK;
}

static struct saxcontenthandler_iface *saxreader_get_contenthandler(saxreader *reader)
{
273
    return &reader->saxhandlers[SAXContentHandler].u.content;
274 275 276 277
}

static struct saxerrorhandler_iface *saxreader_get_errorhandler(saxreader *reader)
{
278
    return &reader->saxhandlers[SAXErrorHandler].u.error;
279 280 281 282
}

static struct saxlexicalhandler_iface *saxreader_get_lexicalhandler(saxreader *reader)
{
283
    return &reader->saxhandlers[SAXLexicalHandler].u.lexical;
284 285
}

286
typedef struct
287
{
288 289
    IVBSAXLocator IVBSAXLocator_iface;
    ISAXLocator ISAXLocator_iface;
290 291
    IVBSAXAttributes IVBSAXAttributes_iface;
    ISAXAttributes ISAXAttributes_iface;
292 293
    LONG ref;
    saxreader *saxreader;
294 295
    HRESULT ret;
    xmlParserCtxtPtr pParserCtxt;
296 297
    BSTR publicId;
    BSTR systemId;
298 299
    int line;
    int column;
300
    BOOL vbInterface;
301
    struct list elements;
302

303
    BSTR namespaceUri;
304 305
    int attr_alloc_count;
    int attr_count;
306 307 308 309 310 311 312
    struct _attributes
    {
        BSTR szLocalname;
        BSTR szURI;
        BSTR szValue;
        BSTR szQName;
    } *attributes;
313
} saxlocator;
314

315 316
static inline saxreader *impl_from_IVBSAXXMLReader( IVBSAXXMLReader *iface )
{
317
    return CONTAINING_RECORD(iface, saxreader, IVBSAXXMLReader_iface);
318
}
319

320 321
static inline saxreader *impl_from_ISAXXMLReader( ISAXXMLReader *iface )
{
322
    return CONTAINING_RECORD(iface, saxreader, ISAXXMLReader_iface);
323 324
}

325 326
static inline saxlocator *impl_from_IVBSAXLocator( IVBSAXLocator *iface )
{
327
    return CONTAINING_RECORD(iface, saxlocator, IVBSAXLocator_iface);
328 329
}

330 331
static inline saxlocator *impl_from_ISAXLocator( ISAXLocator *iface )
{
332
    return CONTAINING_RECORD(iface, saxlocator, ISAXLocator_iface);
333 334
}

335
static inline saxlocator *impl_from_IVBSAXAttributes( IVBSAXAttributes *iface )
336
{
337
    return CONTAINING_RECORD(iface, saxlocator, IVBSAXAttributes_iface);
338 339
}

340
static inline saxlocator *impl_from_ISAXAttributes( ISAXAttributes *iface )
341
{
342
    return CONTAINING_RECORD(iface, saxlocator, ISAXAttributes_iface);
343 344
}

345
static inline BOOL saxreader_has_handler(const saxlocator *locator, enum saxhandler_type type)
346
{
347 348
    struct saxanyhandler_iface *iface = &locator->saxreader->saxhandlers[type].u.anyhandler;
    return (locator->vbInterface && iface->vbhandler) || (!locator->vbInterface && iface->handler);
349 350
}

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
static HRESULT saxreader_saxcharacters(saxlocator *locator, BSTR chars)
{
    struct saxcontenthandler_iface *content = saxreader_get_contenthandler(locator->saxreader);
    HRESULT hr;

    if (!saxreader_has_handler(locator, SAXContentHandler)) return S_OK;

    if (locator->vbInterface)
        hr = IVBSAXContentHandler_characters(content->vbhandler, &chars);
    else
        hr = ISAXContentHandler_characters(content->handler, chars, SysStringLen(chars));

    return hr;
}

366 367 368 369
/* property names */
static const WCHAR PropertyCharsetW[] = {
    'c','h','a','r','s','e','t',0
};
370 371 372
static const WCHAR PropertyXmlDeclVersionW[] = {
    'x','m','l','d','e','c','l','-','v','e','r','s','i','o','n',0
};
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
static const WCHAR PropertyDeclHandlerW[] = {
    'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/',
    's','a','x','/','p','r','o','p','e','r','t','i','e','s','/',
    'd','e','c','l','a','r','a','t','i','o','n',
    '-','h','a','n','d','l','e','r',0
};
static const WCHAR PropertyDomNodeW[] = {
    'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/',
    's','a','x','/','p','r','o','p','e','r','t','i','e','s','/',
    'd','o','m','-','n','o','d','e',0
};
static const WCHAR PropertyInputSourceW[] = {
    'i','n','p','u','t','-','s','o','u','r','c','e',0
};
static const WCHAR PropertyLexicalHandlerW[] = {
    'h','t','t','p',':','/','/','x','m','l','.','o','r','g','/',
    's','a','x','/','p','r','o','p','e','r','t','i','e','s','/',
    'l','e','x','i','c','a','l','-','h','a','n','d','l','e','r',0
};
static const WCHAR PropertyMaxElementDepthW[] = {
    'm','a','x','-','e','l','e','m','e','n','t','-','d','e','p','t','h',0
};
static const WCHAR PropertyMaxXMLSizeW[] = {
    'm','a','x','-','x','m','l','-','s','i','z','e',0
};
static const WCHAR PropertySchemaDeclHandlerW[] = {
    's','c','h','e','m','a','-','d','e','c','l','a','r','a','t','i','o','n','-',
    'h','a','n','d','l','e','r',0
};
static const WCHAR PropertyXMLDeclEncodingW[] = {
    'x','m','l','d','e','c','l','-','e','n','c','o','d','i','n','g',0
};
static const WCHAR PropertyXMLDeclStandaloneW[] = {
    'x','m','l','d','e','c','l','-','s','t','a','n','d','a','l','o','n','e',0
};
static const WCHAR PropertyXMLDeclVersionW[] = {
    'x','m','l','d','e','c','l','-','v','e','r','s','i','o','n',0
};

412
static inline HRESULT set_feature_value(saxreader *reader, saxreader_feature feature, VARIANT_BOOL value)
413
{
414 415 416 417 418 419
    /* handling of non-VARIANT_* values is version dependent */
    if ((reader->version <  MSXML4) && (value != VARIANT_TRUE))
        value = VARIANT_FALSE;
    if ((reader->version >= MSXML4) && (value != VARIANT_FALSE))
        value = VARIANT_TRUE;

420 421 422 423 424 425 426 427
    if (value == VARIANT_TRUE)
        reader->features |=  feature;
    else
        reader->features &= ~feature;

    return S_OK;
}

428
static inline HRESULT get_feature_value(const saxreader *reader, saxreader_feature feature, VARIANT_BOOL *value)
429 430 431 432 433
{
    *value = reader->features & feature ? VARIANT_TRUE : VARIANT_FALSE;
    return S_OK;
}

434 435 436 437 438
static BOOL is_namespaces_enabled(const saxreader *reader)
{
    return (reader->version < MSXML4) || (reader->features & Namespaces);
}

439
static BSTR build_qname(BSTR prefix, BSTR local)
440
{
441
    if (prefix && *prefix)
442
    {
443 444
        BSTR qname = SysAllocStringLen(NULL, SysStringLen(prefix) + SysStringLen(local) + 1);
        WCHAR *ptr;
445

446 447 448 449 450 451
        ptr = qname;
        strcpyW(ptr, prefix);
        ptr += SysStringLen(prefix);
        *ptr++ = ':';
        strcpyW(ptr, local);
        return qname;
452
    }
453 454 455 456 457 458 459 460 461
    else
        return SysAllocString(local);
}

static element_entry* alloc_element_entry(const xmlChar *local, const xmlChar *prefix, int nb_ns,
    const xmlChar **namespaces)
{
    element_entry *ret;
    int i;
462

463 464 465 466 467 468 469 470 471 472
    ret = heap_alloc(sizeof(*ret));
    if (!ret) return ret;

    ret->local  = bstr_from_xmlChar(local);
    ret->prefix = bstr_from_xmlChar(prefix);
    ret->qname  = build_qname(ret->prefix, ret->local);
    ret->ns = nb_ns ? heap_alloc(nb_ns*sizeof(ns)) : NULL;
    ret->ns_count = nb_ns;

    for (i=0; i < nb_ns; i++)
473
    {
474 475
        ret->ns[i].prefix = bstr_from_xmlChar(namespaces[2*i]);
        ret->ns[i].uri = bstr_from_xmlChar(namespaces[2*i+1]);
476
    }
477 478 479 480 481 482 483 484 485

    return ret;
}

static void free_element_entry(element_entry *element)
{
    int i;

    for (i=0; i<element->ns_count;i++)
486
    {
487 488
        SysFreeString(element->ns[i].prefix);
        SysFreeString(element->ns[i].uri);
489 490
    }

491 492
    SysFreeString(element->prefix);
    SysFreeString(element->local);
Jacek Caban's avatar
Jacek Caban committed
493
    SysFreeString(element->qname);
494

495 496
    heap_free(element->ns);
    heap_free(element);
497 498
}

499
static void push_element_ns(saxlocator *locator, element_entry *element)
500
{
501 502
    list_add_head(&locator->elements, &element->entry);
}
503

504 505 506 507 508 509 510 511
static element_entry * pop_element_ns(saxlocator *locator)
{
    element_entry *element = LIST_ENTRY(list_head(&locator->elements), element_entry, entry);

    if (element)
        list_remove(&element->entry);

    return element;
512 513
}

514
static BSTR find_element_uri(saxlocator *locator, const xmlChar *uri)
515
{
516 517
    element_entry *element;
    BSTR uriW;
518 519
    int i;

520 521 522 523 524
    if (!uri) return NULL;

    uriW = bstr_from_xmlChar(uri);

    LIST_FOR_EACH_ENTRY(element, &locator->elements, element_entry, entry)
525
    {
526 527 528 529 530 531
        for (i=0; i < element->ns_count; i++)
            if (!strcmpW(uriW, element->ns[i].uri))
            {
                SysFreeString(uriW);
                return element->ns[i].uri;
            }
532 533
    }

534 535
    SysFreeString(uriW);
    ERR("namespace uri not found, %s\n", debugstr_a((char*)uri));
536 537 538
    return NULL;
}

539 540 541
/* used to localize version dependent error check behaviour */
static inline BOOL sax_callback_failed(saxlocator *This, HRESULT hr)
{
542
    return This->saxreader->version >= MSXML4 ? FAILED(hr) : hr != S_OK;
543 544 545 546 547
}

/* index value -1 means it tries to loop for a first time */
static inline BOOL iterate_endprefix_index(saxlocator *This, const element_entry *element, int *i)
{
548
    if (This->saxreader->version >= MSXML4)
549 550 551 552 553 554 555 556 557 558 559
    {
        if (*i == -1) *i = 0; else ++*i;
        return *i < element->ns_count;
    }
    else
    {
        if (*i == -1) *i = element->ns_count-1; else --*i;
        return *i >= 0;
    }
}

560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
static BOOL bstr_pool_insert(struct bstrpool *pool, BSTR pool_entry)
{
    if (!pool->pool)
    {
        pool->pool = HeapAlloc(GetProcessHeap(), 0, 16 * sizeof(*pool->pool));
        if (!pool->pool)
            return FALSE;

        pool->index = 0;
        pool->len = 16;
    }
    else if (pool->index == pool->len)
    {
        BSTR *realloc = HeapReAlloc(GetProcessHeap(), 0, pool->pool, pool->len * 2 * sizeof(*realloc));

        if (!realloc)
            return FALSE;

        pool->pool = realloc;
        pool->len *= 2;
    }

    pool->pool[pool->index++] = pool_entry;
    return TRUE;
}

static void free_bstr_pool(struct bstrpool *pool)
{
    unsigned int i;

    for (i = 0; i < pool->index; i++)
        SysFreeString(pool->pool[i]);

    HeapFree(GetProcessHeap(), 0, pool->pool);

    pool->pool = NULL;
    pool->index = pool->len = 0;
}

599
static BSTR bstr_from_xmlCharN(const xmlChar *buf, int len)
600 601 602 603 604 605 606 607 608
{
    DWORD dLen;
    BSTR bstr;

    if (!buf)
        return NULL;

    dLen = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, NULL, 0);
    if(len != -1) dLen++;
609 610
    bstr = SysAllocStringLen(NULL, dLen-1);
    if (!bstr)
611
        return NULL;
612 613
    MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, bstr, dLen);
    if(len != -1) bstr[dLen-1] = '\0';
614 615 616 617

    return bstr;
}

618 619
static BSTR QName_from_xmlChar(const xmlChar *prefix, const xmlChar *name)
{
620
    xmlChar *qname;
621 622 623 624
    BSTR bstr;

    if(!name) return NULL;

625
    if(!prefix || !*prefix)
626 627
        return bstr_from_xmlChar(name);

628 629 630
    qname = xmlBuildQName(name, prefix, NULL, 0);
    bstr = bstr_from_xmlChar(qname);
    xmlFree(qname);
631 632 633 634

    return bstr;
}

635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
static BSTR pooled_bstr_from_xmlChar(struct bstrpool *pool, const xmlChar *buf)
{
    BSTR pool_entry = bstr_from_xmlChar(buf);

    if (pool_entry && !bstr_pool_insert(pool, pool_entry))
    {
        SysFreeString(pool_entry);
        return NULL;
    }

    return pool_entry;
}

static BSTR pooled_bstr_from_xmlCharN(struct bstrpool *pool, const xmlChar *buf, int len)
{
    BSTR pool_entry = bstr_from_xmlCharN(buf, len);

    if (pool_entry && !bstr_pool_insert(pool, pool_entry))
    {
        SysFreeString(pool_entry);
        return NULL;
    }

    return pool_entry;
}

661 662
static void format_error_message_from_id(saxlocator *This, HRESULT hr)
{
663
    struct saxerrorhandler_iface *handler = saxreader_get_errorhandler(This->saxreader);
664 665 666
    xmlStopParser(This->pParserCtxt);
    This->ret = hr;

667
    if (saxreader_has_handler(This, SAXErrorHandler))
668 669 670
    {
        WCHAR msg[1024];
        if(!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
671
                    NULL, hr, 0, msg, sizeof(msg)/sizeof(msg[0]), NULL))
672 673 674 675 676
        {
            FIXME("MSXML errors not yet supported.\n");
            msg[0] = '\0';
        }

677 678 679
        if(This->vbInterface)
        {
            BSTR bstrMsg = SysAllocString(msg);
680
            IVBSAXErrorHandler_fatalError(handler->vbhandler,
681
                    &This->IVBSAXLocator_iface, &bstrMsg, hr);
682
            SysFreeString(bstrMsg);
683 684
        }
        else
685
            ISAXErrorHandler_fatalError(handler->handler,
686
                    &This->ISAXLocator_iface, msg, hr);
687 688 689
    }
}

690
static void update_position(saxlocator *This, BOOL fix_column)
691
{
692
    const xmlChar *p = This->pParserCtxt->input->cur-1;
693

694 695
    This->line = xmlSAX2GetLineNumber(This->pParserCtxt);
    if(fix_column)
696
    {
697 698 699
        This->column = 1;
        for(; *p!='\n' && *p!='\r' && p>=This->pParserCtxt->input->base; p--)
            This->column++;
700
    }
701
    else
702
    {
703
        This->column = xmlSAX2GetColumnNumber(This->pParserCtxt);
704 705 706
    }
}

707 708 709 710 711 712
/*** IVBSAXAttributes interface ***/
static HRESULT WINAPI ivbsaxattributes_QueryInterface(
        IVBSAXAttributes* iface,
        REFIID riid,
        void **ppvObject)
{
713
    saxlocator *This = impl_from_IVBSAXAttributes(iface);
714
    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
715
    return IVBSAXLocator_QueryInterface(&This->IVBSAXLocator_iface, riid, ppvObject);
716 717 718 719
}

static ULONG WINAPI ivbsaxattributes_AddRef(IVBSAXAttributes* iface)
{
720
    saxlocator *This = impl_from_IVBSAXAttributes(iface);
721
    return IVBSAXLocator_AddRef(&This->IVBSAXLocator_iface);
722 723 724 725
}

static ULONG WINAPI ivbsaxattributes_Release(IVBSAXAttributes* iface)
{
726
    saxlocator *This = impl_from_IVBSAXAttributes(iface);
727
    return IVBSAXLocator_Release(&This->IVBSAXLocator_iface);
728 729 730 731
}

static HRESULT WINAPI ivbsaxattributes_GetTypeInfoCount( IVBSAXAttributes *iface, UINT* pctinfo )
{
732
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
733 734 735 736 737 738

    TRACE("(%p)->(%p)\n", This, pctinfo);

    *pctinfo = 1;

    return S_OK;
739 740
}

741 742
static HRESULT WINAPI ivbsaxattributes_GetTypeInfo(
    IVBSAXAttributes *iface,
743
    UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
744
{
745
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
746

747 748
    TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);

749
    return get_typeinfo(IVBSAXAttributes_tid, ppTInfo);
750 751 752 753 754 755 756 757 758 759
}

static HRESULT WINAPI ivbsaxattributes_GetIDsOfNames(
    IVBSAXAttributes *iface,
    REFIID riid,
    LPOLESTR* rgszNames,
    UINT cNames,
    LCID lcid,
    DISPID* rgDispId)
{
760
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
761 762 763 764 765 766 767 768 769 770 771
    ITypeInfo *typeinfo;
    HRESULT hr;

    TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
          lcid, rgDispId);

    if(!rgszNames || cNames == 0 || !rgDispId)
        return E_INVALIDARG;

    hr = get_typeinfo(IVBSAXAttributes_tid, &typeinfo);
    if(SUCCEEDED(hr))
772
    {
773
        hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
774 775
        ITypeInfo_Release(typeinfo);
    }
776 777

    return hr;
778 779 780 781 782 783 784
}

static HRESULT WINAPI ivbsaxattributes_Invoke(
    IVBSAXAttributes *iface,
    DISPID dispIdMember,
    REFIID riid,
    LCID lcid,
785
    WORD wFlags,
786 787 788 789 790
    DISPPARAMS* pDispParams,
    VARIANT* pVarResult,
    EXCEPINFO* pExcepInfo,
    UINT* puArgErr)
{
791
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
792 793 794 795 796 797 798 799
    ITypeInfo *typeinfo;
    HRESULT hr;

    TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
          lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);

    hr = get_typeinfo(IVBSAXAttributes_tid, &typeinfo);
    if(SUCCEEDED(hr))
800
    {
801 802
        hr = ITypeInfo_Invoke(typeinfo, &This->IVBSAXAttributes_iface, dispIdMember, wFlags,
                pDispParams, pVarResult, pExcepInfo, puArgErr);
803 804
        ITypeInfo_Release(typeinfo);
    }
805 806

    return hr;
807 808 809 810 811 812 813
}

/*** IVBSAXAttributes methods ***/
static HRESULT WINAPI ivbsaxattributes_get_length(
        IVBSAXAttributes* iface,
        int *nLength)
{
814
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
815
    return ISAXAttributes_getLength(&This->ISAXAttributes_iface, nLength);
816 817 818 819 820 821 822
}

static HRESULT WINAPI ivbsaxattributes_getURI(
        IVBSAXAttributes* iface,
        int nIndex,
        BSTR *uri)
{
823
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
    const WCHAR *uriW;
    HRESULT hr;
    int len;

    TRACE("(%p)->(%d %p)\n", This, nIndex, uri);

    if (!uri)
        return E_POINTER;

    *uri = NULL;
    hr = ISAXAttributes_getURI(&This->ISAXAttributes_iface, nIndex, &uriW, &len);
    if (FAILED(hr))
        return hr;

    return return_bstrn(uriW, len, uri);
839 840
}

841 842 843
static HRESULT WINAPI ivbsaxattributes_getLocalName(
        IVBSAXAttributes* iface,
        int nIndex,
844
        BSTR *name)
845
{
846
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
    const WCHAR *nameW;
    HRESULT hr;
    int len;

    TRACE("(%p)->(%d %p)\n", This, nIndex, name);

    if (!name)
        return E_POINTER;

    *name = NULL;
    hr = ISAXAttributes_getLocalName(&This->ISAXAttributes_iface, nIndex, &nameW, &len);
    if (FAILED(hr))
        return hr;

    return return_bstrn(nameW, len, name);
862 863
}

864 865 866 867
static HRESULT WINAPI ivbsaxattributes_getQName(
        IVBSAXAttributes* iface,
        int nIndex,
        BSTR *QName)
868
{
869
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
    const WCHAR *nameW;
    HRESULT hr;
    int len;

    TRACE("(%p)->(%d %p)\n", This, nIndex, QName);

    if (!QName)
        return E_POINTER;

    *QName = NULL;
    hr = ISAXAttributes_getQName(&This->ISAXAttributes_iface, nIndex, &nameW, &len);
    if (FAILED(hr))
        return hr;

    return return_bstrn(nameW, len, QName);
885 886
}

887 888 889 890 891
static HRESULT WINAPI ivbsaxattributes_getIndexFromName(
        IVBSAXAttributes* iface,
        BSTR uri,
        BSTR localName,
        int *index)
892
{
893
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
894 895
    return ISAXAttributes_getIndexFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
            localName, SysStringLen(localName), index);
896 897
}

898 899 900 901
static HRESULT WINAPI ivbsaxattributes_getIndexFromQName(
        IVBSAXAttributes* iface,
        BSTR QName,
        int *index)
902
{
903
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
904 905
    return ISAXAttributes_getIndexFromQName(&This->ISAXAttributes_iface, QName,
            SysStringLen(QName), index);
906 907
}

908 909 910 911
static HRESULT WINAPI ivbsaxattributes_getType(
        IVBSAXAttributes* iface,
        int nIndex,
        BSTR *type)
912
{
913
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
    const WCHAR *typeW;
    HRESULT hr;
    int len;

    TRACE("(%p)->(%d %p)\n", This, nIndex, type);

    if (!type)
        return E_POINTER;

    *type = NULL;
    hr = ISAXAttributes_getType(&This->ISAXAttributes_iface, nIndex, &typeW, &len);
    if (FAILED(hr))
        return hr;

    return return_bstrn(typeW, len, type);
929 930
}

931 932 933 934 935
static HRESULT WINAPI ivbsaxattributes_getTypeFromName(
        IVBSAXAttributes* iface,
        BSTR uri,
        BSTR localName,
        BSTR *type)
936
{
937
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
    const WCHAR *typeW;
    HRESULT hr;
    int len;

    TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(uri), debugstr_w(localName), type);

    if (!type)
        return E_POINTER;

    *type = NULL;
    hr = ISAXAttributes_getTypeFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
            localName, SysStringLen(localName), &typeW, &len);
    if (FAILED(hr))
        return hr;

    return return_bstrn(typeW, len, type);
954 955
}

956 957 958 959
static HRESULT WINAPI ivbsaxattributes_getTypeFromQName(
        IVBSAXAttributes* iface,
        BSTR QName,
        BSTR *type)
960
{
961
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
    const WCHAR *typeW;
    HRESULT hr;
    int len;

    TRACE("(%p)->(%s %p)\n", This, debugstr_w(QName), type);

    if (!type)
        return E_POINTER;

    *type = NULL;
    hr = ISAXAttributes_getTypeFromQName(&This->ISAXAttributes_iface, QName, SysStringLen(QName),
            &typeW, &len);
    if (FAILED(hr))
        return hr;

    return return_bstrn(typeW, len, type);
978 979
}

980 981 982 983
static HRESULT WINAPI ivbsaxattributes_getValue(
        IVBSAXAttributes* iface,
        int nIndex,
        BSTR *value)
984
{
985
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
    const WCHAR *valueW;
    HRESULT hr;
    int len;

    TRACE("(%p)->(%d %p)\n", This, nIndex, value);

    if (!value)
        return E_POINTER;

    *value = NULL;
    hr = ISAXAttributes_getValue(&This->ISAXAttributes_iface, nIndex, &valueW, &len);
    if (FAILED(hr))
        return hr;

    return return_bstrn(valueW, len, value);
1001 1002
}

1003 1004 1005 1006 1007
static HRESULT WINAPI ivbsaxattributes_getValueFromName(
        IVBSAXAttributes* iface,
        BSTR uri,
        BSTR localName,
        BSTR *value)
1008
{
1009
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
    const WCHAR *valueW;
    HRESULT hr;
    int len;

    TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(uri), debugstr_w(localName), value);

    if (!value)
        return E_POINTER;

    *value = NULL;
    hr = ISAXAttributes_getValueFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
            localName, SysStringLen(localName), &valueW, &len);
    if (FAILED(hr))
        return hr;

    return return_bstrn(valueW, len, value);
1026 1027
}

1028 1029 1030 1031
static HRESULT WINAPI ivbsaxattributes_getValueFromQName(
        IVBSAXAttributes* iface,
        BSTR QName,
        BSTR *value)
1032
{
1033
    saxlocator *This = impl_from_IVBSAXAttributes( iface );
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
    const WCHAR *valueW;
    HRESULT hr;
    int len;

    TRACE("(%p)->(%s %p)\n", This, debugstr_w(QName), value);

    if (!value)
        return E_POINTER;

    *value = NULL;
    hr = ISAXAttributes_getValueFromQName(&This->ISAXAttributes_iface, QName,
            SysStringLen(QName), &valueW, &len);
    if (FAILED(hr))
        return hr;

    return return_bstrn(valueW, len, value);
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
}

static const struct IVBSAXAttributesVtbl ivbsaxattributes_vtbl =
{
    ivbsaxattributes_QueryInterface,
    ivbsaxattributes_AddRef,
    ivbsaxattributes_Release,
    ivbsaxattributes_GetTypeInfoCount,
    ivbsaxattributes_GetTypeInfo,
    ivbsaxattributes_GetIDsOfNames,
    ivbsaxattributes_Invoke,
    ivbsaxattributes_get_length,
    ivbsaxattributes_getURI,
    ivbsaxattributes_getLocalName,
    ivbsaxattributes_getQName,
    ivbsaxattributes_getIndexFromName,
    ivbsaxattributes_getIndexFromQName,
    ivbsaxattributes_getType,
    ivbsaxattributes_getTypeFromName,
    ivbsaxattributes_getTypeFromQName,
    ivbsaxattributes_getValue,
    ivbsaxattributes_getValueFromName,
    ivbsaxattributes_getValueFromQName
};

1075 1076 1077 1078 1079 1080 1081
/*** ISAXAttributes interface ***/
/*** IUnknown methods ***/
static HRESULT WINAPI isaxattributes_QueryInterface(
        ISAXAttributes* iface,
        REFIID riid,
        void **ppvObject)
{
1082
    saxlocator *This = impl_from_ISAXAttributes(iface);
1083
    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
1084
    return ISAXLocator_QueryInterface(&This->ISAXLocator_iface, riid, ppvObject);
1085 1086 1087 1088
}

static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
{
1089
    saxlocator *This = impl_from_ISAXAttributes(iface);
1090
    TRACE("%p\n", This);
1091
    return ISAXLocator_AddRef(&This->ISAXLocator_iface);
1092 1093 1094 1095
}

static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
{
1096
    saxlocator *This = impl_from_ISAXAttributes(iface);
1097

1098
    TRACE("%p\n", This);
1099
    return ISAXLocator_Release(&This->ISAXLocator_iface);
1100 1101 1102
}

/*** ISAXAttributes methods ***/
1103 1104 1105
static HRESULT WINAPI isaxattributes_getLength(
        ISAXAttributes* iface,
        int *length)
1106
{
1107
    saxlocator *This = impl_from_ISAXAttributes( iface );
1108

1109
    *length = This->attr_count;
1110 1111
    TRACE("Length set to %d\n", *length);
    return S_OK;
1112 1113
}

1114 1115 1116 1117 1118
static inline BOOL is_valid_attr_index(const saxlocator *locator, int index)
{
    return index < locator->attr_count && index >= 0;
}

1119 1120 1121 1122 1123
static HRESULT WINAPI isaxattributes_getURI(
        ISAXAttributes* iface,
        int index,
        const WCHAR **url,
        int *size)
1124
{
1125
    saxlocator *This = impl_from_ISAXAttributes( iface );
1126 1127
    TRACE("(%p)->(%d)\n", This, index);

1128
    if(!is_valid_attr_index(This, index)) return E_INVALIDARG;
1129 1130 1131 1132 1133 1134 1135 1136
    if(!url || !size) return E_POINTER;

    *size = SysStringLen(This->attributes[index].szURI);
    *url = This->attributes[index].szURI;

    TRACE("(%s:%d)\n", debugstr_w(This->attributes[index].szURI), *size);

    return S_OK;
1137 1138
}

1139 1140
static HRESULT WINAPI isaxattributes_getLocalName(
        ISAXAttributes* iface,
1141
        int index,
1142 1143
        const WCHAR **pLocalName,
        int *pLocalNameLength)
1144
{
1145
    saxlocator *This = impl_from_ISAXAttributes( iface );
1146
    TRACE("(%p)->(%d)\n", This, index);
1147

1148
    if(!is_valid_attr_index(This, index)) return E_INVALIDARG;
1149 1150
    if(!pLocalName || !pLocalNameLength) return E_POINTER;

1151 1152
    *pLocalNameLength = SysStringLen(This->attributes[index].szLocalname);
    *pLocalName = This->attributes[index].szLocalname;
1153 1154

    return S_OK;
1155 1156
}

1157 1158
static HRESULT WINAPI isaxattributes_getQName(
        ISAXAttributes* iface,
1159
        int index,
1160 1161
        const WCHAR **pQName,
        int *pQNameLength)
1162
{
1163
    saxlocator *This = impl_from_ISAXAttributes( iface );
1164
    TRACE("(%p)->(%d)\n", This, index);
1165

1166
    if(!is_valid_attr_index(This, index)) return E_INVALIDARG;
1167 1168
    if(!pQName || !pQNameLength) return E_POINTER;

1169 1170
    *pQNameLength = SysStringLen(This->attributes[index].szQName);
    *pQName = This->attributes[index].szQName;
1171 1172

    return S_OK;
1173 1174
}

1175 1176 1177 1178 1179 1180 1181 1182 1183
static HRESULT WINAPI isaxattributes_getName(
        ISAXAttributes* iface,
        int index,
        const WCHAR **uri,
        int *pUriLength,
        const WCHAR **localName,
        int *pLocalNameSize,
        const WCHAR **QName,
        int *pQNameLength)
1184
{
1185
    saxlocator *This = impl_from_ISAXAttributes( iface );
1186 1187
    TRACE("(%p)->(%d)\n", This, index);

1188
    if(!is_valid_attr_index(This, index)) return E_INVALIDARG;
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
    if(!uri || !pUriLength || !localName || !pLocalNameSize
            || !QName || !pQNameLength) return E_POINTER;

    *pUriLength = SysStringLen(This->attributes[index].szURI);
    *uri = This->attributes[index].szURI;
    *pLocalNameSize = SysStringLen(This->attributes[index].szLocalname);
    *localName = This->attributes[index].szLocalname;
    *pQNameLength = SysStringLen(This->attributes[index].szQName);
    *QName = This->attributes[index].szQName;

    TRACE("(%s, %s, %s)\n", debugstr_w(*uri), debugstr_w(*localName), debugstr_w(*QName));

    return S_OK;
1202 1203
}

1204 1205 1206 1207 1208 1209 1210
static HRESULT WINAPI isaxattributes_getIndexFromName(
        ISAXAttributes* iface,
        const WCHAR *pUri,
        int cUriLength,
        const WCHAR *pLocalName,
        int cocalNameLength,
        int *index)
1211
{
1212
    saxlocator *This = impl_from_ISAXAttributes( iface );
1213 1214 1215 1216 1217 1218
    int i;
    TRACE("(%p)->(%s, %d, %s, %d)\n", This, debugstr_w(pUri), cUriLength,
            debugstr_w(pLocalName), cocalNameLength);

    if(!pUri || !pLocalName || !index) return E_POINTER;

1219
    for(i=0; i<This->attr_count; i++)
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
    {
        if(cUriLength!=SysStringLen(This->attributes[i].szURI)
                || cocalNameLength!=SysStringLen(This->attributes[i].szLocalname))
            continue;
        if(cUriLength && memcmp(pUri, This->attributes[i].szURI,
                    sizeof(WCHAR)*cUriLength))
            continue;
        if(cocalNameLength && memcmp(pLocalName, This->attributes[i].szLocalname,
                    sizeof(WCHAR)*cocalNameLength))
            continue;

        *index = i;
        return S_OK;
    }

    return E_INVALIDARG;
1236 1237
}

1238 1239 1240 1241 1242
static HRESULT WINAPI isaxattributes_getIndexFromQName(
        ISAXAttributes* iface,
        const WCHAR *pQName,
        int nQNameLength,
        int *index)
1243
{
1244
    saxlocator *This = impl_from_ISAXAttributes( iface );
1245 1246 1247 1248 1249 1250
    int i;
    TRACE("(%p)->(%s, %d)\n", This, debugstr_w(pQName), nQNameLength);

    if(!pQName || !index) return E_POINTER;
    if(!nQNameLength) return E_INVALIDARG;

1251
    for(i=0; i<This->attr_count; i++)
1252 1253 1254 1255 1256 1257 1258 1259 1260
    {
        if(nQNameLength!=SysStringLen(This->attributes[i].szQName)) continue;
        if(memcmp(pQName, This->attributes[i].szQName, sizeof(WCHAR)*nQNameLength)) continue;

        *index = i;
        return S_OK;
    }

    return E_INVALIDARG;
1261 1262
}

1263 1264 1265 1266 1267
static HRESULT WINAPI isaxattributes_getType(
        ISAXAttributes* iface,
        int nIndex,
        const WCHAR **pType,
        int *pTypeLength)
1268
{
1269
    saxlocator *This = impl_from_ISAXAttributes( iface );
1270 1271 1272

    FIXME("(%p)->(%d) stub\n", This, nIndex);
    return E_NOTIMPL;
1273 1274
}

1275 1276 1277 1278 1279 1280 1281 1282
static HRESULT WINAPI isaxattributes_getTypeFromName(
        ISAXAttributes* iface,
        const WCHAR *pUri,
        int nUri,
        const WCHAR *pLocalName,
        int nLocalName,
        const WCHAR **pType,
        int *nType)
1283
{
1284
    saxlocator *This = impl_from_ISAXAttributes( iface );
1285 1286 1287 1288

    FIXME("(%p)->(%s, %d, %s, %d) stub\n", This, debugstr_w(pUri), nUri,
            debugstr_w(pLocalName), nLocalName);
    return E_NOTIMPL;
1289 1290
}

1291 1292 1293 1294 1295 1296
static HRESULT WINAPI isaxattributes_getTypeFromQName(
        ISAXAttributes* iface,
        const WCHAR *pQName,
        int nQName,
        const WCHAR **pType,
        int *nType)
1297
{
1298
    saxlocator *This = impl_from_ISAXAttributes( iface );
1299 1300 1301

    FIXME("(%p)->(%s, %d) stub\n", This, debugstr_w(pQName), nQName);
    return E_NOTIMPL;
1302 1303
}

1304 1305 1306 1307 1308
static HRESULT WINAPI isaxattributes_getValue(
        ISAXAttributes* iface,
        int index,
        const WCHAR **value,
        int *nValue)
1309
{
1310
    saxlocator *This = impl_from_ISAXAttributes( iface );
1311 1312
    TRACE("(%p)->(%d)\n", This, index);

1313
    if(!is_valid_attr_index(This, index)) return E_INVALIDARG;
1314 1315 1316 1317 1318 1319 1320 1321
    if(!value || !nValue) return E_POINTER;

    *nValue = SysStringLen(This->attributes[index].szValue);
    *value = This->attributes[index].szValue;

    TRACE("(%s:%d)\n", debugstr_w(*value), *nValue);

    return S_OK;
1322 1323
}

1324 1325 1326 1327 1328 1329 1330 1331
static HRESULT WINAPI isaxattributes_getValueFromName(
        ISAXAttributes* iface,
        const WCHAR *pUri,
        int nUri,
        const WCHAR *pLocalName,
        int nLocalName,
        const WCHAR **pValue,
        int *nValue)
1332
{
1333 1334
    HRESULT hr;
    int index;
1335
    saxlocator *This = impl_from_ISAXAttributes( iface );
1336 1337 1338 1339 1340 1341 1342 1343
    TRACE("(%p)->(%s, %d, %s, %d)\n", This, debugstr_w(pUri), nUri,
            debugstr_w(pLocalName), nLocalName);

    hr = ISAXAttributes_getIndexFromName(iface,
            pUri, nUri, pLocalName, nLocalName, &index);
    if(hr==S_OK) hr = ISAXAttributes_getValue(iface, index, pValue, nValue);

    return hr;
1344 1345
}

1346 1347 1348 1349 1350 1351
static HRESULT WINAPI isaxattributes_getValueFromQName(
        ISAXAttributes* iface,
        const WCHAR *pQName,
        int nQName,
        const WCHAR **pValue,
        int *nValue)
1352
{
1353 1354
    HRESULT hr;
    int index;
1355
    saxlocator *This = impl_from_ISAXAttributes( iface );
1356 1357 1358 1359 1360 1361
    TRACE("(%p)->(%s, %d)\n", This, debugstr_w(pQName), nQName);

    hr = ISAXAttributes_getIndexFromQName(iface, pQName, nQName, &index);
    if(hr==S_OK) hr = ISAXAttributes_getValue(iface, index, pValue, nValue);

    return hr;
1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
}

static const struct ISAXAttributesVtbl isaxattributes_vtbl =
{
    isaxattributes_QueryInterface,
    isaxattributes_AddRef,
    isaxattributes_Release,
    isaxattributes_getLength,
    isaxattributes_getURI,
    isaxattributes_getLocalName,
    isaxattributes_getQName,
    isaxattributes_getName,
    isaxattributes_getIndexFromName,
    isaxattributes_getIndexFromQName,
    isaxattributes_getType,
    isaxattributes_getTypeFromName,
    isaxattributes_getTypeFromQName,
    isaxattributes_getValue,
    isaxattributes_getValueFromName,
    isaxattributes_getValueFromQName
};

1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426
/* Libxml2 escapes '&' back to char reference '&#38;' in attribute value,
   so when document has escaped value with '&amp;' it's parsed to '&' and then
   escaped to '&#38;'. This function takes care of ampersands only. */
static BSTR saxreader_get_unescaped_value(const xmlChar *buf, int len)
{
    static const WCHAR ampescW[] = {'&','#','3','8',';',0};
    WCHAR *dest, *ptrW, *str;
    DWORD str_len;
    BSTR bstr;

    if (!buf)
        return NULL;

    str_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, NULL, 0);
    if (len != -1) str_len++;

    str = heap_alloc(str_len*sizeof(WCHAR));
    if (!str) return NULL;

    MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)buf, len, str, str_len);
    if (len != -1) str[str_len-1] = 0;

    ptrW = str;
    while ((dest = strstrW(ptrW, ampescW)))
    {
        WCHAR *src;

        /* leave first '&' from a reference as a value */
        src = dest + (sizeof(ampescW)/sizeof(WCHAR) - 1);
        dest++;

        /* move together with null terminator */
        memmove(dest, src, (strlenW(src) + 1)*sizeof(WCHAR));

        ptrW++;
    }

    bstr = SysAllocString(str);
    heap_free(str);

    return bstr;
}

1427 1428 1429 1430
static void free_attribute_values(saxlocator *locator)
{
    int i;

1431
    for (i = 0; i < locator->attr_count; i++)
1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
    {
        SysFreeString(locator->attributes[i].szLocalname);
        locator->attributes[i].szLocalname = NULL;

        SysFreeString(locator->attributes[i].szValue);
        locator->attributes[i].szValue = NULL;

        SysFreeString(locator->attributes[i].szQName);
        locator->attributes[i].szQName = NULL;
    }
}

1444
static HRESULT SAXAttributes_populate(saxlocator *locator,
1445
        int nb_namespaces, const xmlChar **xmlNamespaces,
1446
        int nb_attributes, const xmlChar **xmlAttributes)
1447
{
1448
    static const xmlChar xmlns[] = "xmlns";
1449 1450 1451
    static const WCHAR xmlnsW[] = { 'x','m','l','n','s',0 };

    struct _attributes *attrs;
1452 1453 1454 1455 1456
    int i;

    /* skip namespace definitions */
    if ((locator->saxreader->features & NamespacePrefixes) == 0)
        nb_namespaces = 0;
1457

1458 1459
    locator->attr_count = nb_namespaces + nb_attributes;
    if(locator->attr_count > locator->attr_alloc_count)
1460
    {
1461
        int new_size = locator->attr_count * 2;
1462
        attrs = heap_realloc_zero(locator->attributes, new_size * sizeof(struct _attributes));
1463 1464
        if(!attrs)
        {
1465
            free_attribute_values(locator);
1466
            locator->attr_count = 0;
1467 1468 1469
            return E_OUTOFMEMORY;
        }
        locator->attributes = attrs;
1470
        locator->attr_alloc_count = new_size;
1471 1472 1473 1474
    }
    else
    {
        attrs = locator->attributes;
1475 1476
    }

1477 1478
    for (i = 0; i < nb_namespaces; i++)
    {
1479
        SysFreeString(attrs[nb_attributes+i].szLocalname);
1480
        attrs[nb_attributes+i].szLocalname = SysAllocStringLen(NULL, 0);
1481

1482
        attrs[nb_attributes+i].szURI = locator->namespaceUri;
1483 1484

        SysFreeString(attrs[nb_attributes+i].szValue);
1485
        attrs[nb_attributes+i].szValue = bstr_from_xmlChar(xmlNamespaces[2*i+1]);
1486 1487

        SysFreeString(attrs[nb_attributes+i].szQName);
1488 1489
        if(!xmlNamespaces[2*i])
            attrs[nb_attributes+i].szQName = SysAllocString(xmlnsW);
1490
        else
1491 1492
            attrs[nb_attributes+i].szQName = QName_from_xmlChar(xmlns, xmlNamespaces[2*i]);
    }
1493

1494 1495 1496
    for (i = 0; i < nb_attributes; i++)
    {
        static const xmlChar xmlA[] = "xml";
1497

1498 1499 1500 1501 1502
        if (xmlStrEqual(xmlAttributes[i*5+1], xmlA))
            attrs[i].szURI = bstr_from_xmlChar(xmlAttributes[i*5+2]);
        else
            /* that's an important feature to keep same uri pointer for every reported attribute */
            attrs[i].szURI = find_element_uri(locator, xmlAttributes[i*5+2]);
1503

1504
        SysFreeString(attrs[i].szLocalname);
1505
        attrs[i].szLocalname = bstr_from_xmlChar(xmlAttributes[i*5]);
1506 1507

        SysFreeString(attrs[i].szValue);
1508
        attrs[i].szValue = saxreader_get_unescaped_value(xmlAttributes[i*5+3], xmlAttributes[i*5+4]-xmlAttributes[i*5+3]);
1509 1510 1511

        SysFreeString(attrs[i].szQName);
        attrs[i].szQName = QName_from_xmlChar(xmlAttributes[i*5+1], xmlAttributes[i*5]);
1512 1513
    }

1514 1515 1516
    return S_OK;
}

1517 1518 1519 1520
/*** LibXML callbacks ***/
static void libxmlStartDocument(void *ctx)
{
    saxlocator *This = ctx;
1521
    struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1522 1523
    HRESULT hr;

1524
    if (This->saxreader->version >= MSXML4)
1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
    {
        const xmlChar *p = This->pParserCtxt->input->cur-1;
        update_position(This, FALSE);
        while(p>This->pParserCtxt->input->base && *p!='>')
        {
            if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
                This->line--;
            p--;
        }
        This->column = 0;
        for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--)
            This->column++;
1537 1538
    }

1539 1540 1541 1542 1543 1544 1545
    /* store version value, declaration has to contain version attribute */
    if (This->pParserCtxt->standalone != -1)
    {
        SysFreeString(This->saxreader->xmldecl_version);
        This->saxreader->xmldecl_version = bstr_from_xmlChar(This->pParserCtxt->version);
    }

1546
    if (saxreader_has_handler(This, SAXContentHandler))
1547
    {
1548
        if(This->vbInterface)
1549
            hr = IVBSAXContentHandler_startDocument(handler->vbhandler);
1550
        else
1551
            hr = ISAXContentHandler_startDocument(handler->handler);
1552

1553
        if (sax_callback_failed(This, hr))
1554
            format_error_message_from_id(This, hr);
1555 1556 1557
    }
}

1558 1559 1560
static void libxmlEndDocument(void *ctx)
{
    saxlocator *This = ctx;
1561
    struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1562 1563
    HRESULT hr;

1564
    if (This->saxreader->version >= MSXML4) {
1565
        update_position(This, FALSE);
1566 1567 1568 1569 1570 1571 1572
        if(This->column > 1)
            This->line++;
        This->column = 0;
    } else {
        This->column = 0;
        This->line = 0;
    }
1573

1574 1575
    if(This->ret != S_OK) return;

1576
    if (saxreader_has_handler(This, SAXContentHandler))
1577
    {
1578
        if(This->vbInterface)
1579
            hr = IVBSAXContentHandler_endDocument(handler->vbhandler);
1580
        else
1581
            hr = ISAXContentHandler_endDocument(handler->handler);
1582

1583
        if (sax_callback_failed(This, hr))
1584
            format_error_message_from_id(This, hr);
1585 1586 1587
    }
}

1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
static void libxmlStartElementNS(
        void *ctx,
        const xmlChar *localname,
        const xmlChar *prefix,
        const xmlChar *URI,
        int nb_namespaces,
        const xmlChar **namespaces,
        int nb_attributes,
        int nb_defaulted,
        const xmlChar **attributes)
{
    saxlocator *This = ctx;
1600
    struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1601 1602
    element_entry *element;
    HRESULT hr = S_OK;
1603
    BSTR uri;
1604

1605
    update_position(This, TRUE);
1606
    if(*(This->pParserCtxt->input->cur) == '/')
1607
        This->column++;
1608
    if(This->saxreader->version < MSXML4)
1609
        This->column++;
1610

1611 1612
    element = alloc_element_entry(localname, prefix, nb_namespaces, namespaces);
    push_element_ns(This, element);
1613

1614
    if (is_namespaces_enabled(This->saxreader))
1615
    {
1616
        int i;
1617

1618
        for (i = 0; i < nb_namespaces && saxreader_has_handler(This, SAXContentHandler); i++)
1619
        {
1620 1621
            if (This->vbInterface)
                hr = IVBSAXContentHandler_startPrefixMapping(
1622
                        handler->vbhandler,
1623 1624 1625 1626
                        &element->ns[i].prefix,
                        &element->ns[i].uri);
            else
                hr = ISAXContentHandler_startPrefixMapping(
1627
                        handler->handler,
1628 1629 1630 1631
                        element->ns[i].prefix,
                        SysStringLen(element->ns[i].prefix),
                        element->ns[i].uri,
                        SysStringLen(element->ns[i].uri));
1632

1633
            if (sax_callback_failed(This, hr))
1634
            {
1635 1636
                format_error_message_from_id(This, hr);
                return;
1637 1638
            }
        }
1639
    }
1640

1641 1642
    uri = find_element_uri(This, URI);
    hr = SAXAttributes_populate(This, nb_namespaces, namespaces, nb_attributes, attributes);
1643
    if (hr == S_OK && saxreader_has_handler(This, SAXContentHandler))
1644 1645
    {
        BSTR local;
1646

1647 1648 1649 1650
        if (is_namespaces_enabled(This->saxreader))
            local = element->local;
        else
            uri = local = NULL;
1651

1652
        if (This->vbInterface)
1653
            hr = IVBSAXContentHandler_startElement(handler->vbhandler,
1654 1655
                    &uri, &local, &element->qname, &This->IVBSAXAttributes_iface);
        else
1656
            hr = ISAXContentHandler_startElement(handler->handler,
1657 1658 1659 1660 1661 1662 1663
                    uri, SysStringLen(uri),
                    local, SysStringLen(local),
                    element->qname, SysStringLen(element->qname),
                    &This->ISAXAttributes_iface);

       if (sax_callback_failed(This, hr))
           format_error_message_from_id(This, hr);
1664 1665 1666
    }
}

1667 1668 1669 1670 1671 1672 1673
static void libxmlEndElementNS(
        void *ctx,
        const xmlChar *localname,
        const xmlChar *prefix,
        const xmlChar *URI)
{
    saxlocator *This = ctx;
1674
    struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1675
    element_entry *element;
1676
    const xmlChar *p;
1677
    BSTR uri, local;
1678
    HRESULT hr;
1679

1680 1681
    update_position(This, FALSE);
    p = This->pParserCtxt->input->cur;
1682 1683

    if (This->saxreader->version >= MSXML4)
1684 1685 1686 1687 1688 1689 1690 1691
    {
        p--;
        while(p>This->pParserCtxt->input->base && *p!='>')
        {
            if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
                This->line--;
            p--;
        }
1692
    }
1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706
    else if(*(p-1)!='>' || *(p-2)!='/')
    {
        p--;
        while(p-2>=This->pParserCtxt->input->base
                && *(p-2)!='<' && *(p-1)!='/')
        {
            if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
                This->line--;
            p--;
        }
    }
    This->column = 0;
    for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--)
        This->column++;
1707

1708 1709
    uri = find_element_uri(This, URI);
    element = pop_element_ns(This);
1710

1711
    if (!saxreader_has_handler(This, SAXContentHandler))
1712
    {
1713
        free_attribute_values(This);
1714
        This->attr_count = 0;
1715 1716 1717
        free_element_entry(element);
        return;
    }
1718

1719 1720 1721 1722 1723 1724
    if (is_namespaces_enabled(This->saxreader))
        local = element->local;
    else
        uri = local = NULL;

    if (This->vbInterface)
1725
        hr = IVBSAXContentHandler_endElement(
1726
                handler->vbhandler,
1727
                &uri, &local, &element->qname);
1728 1729
    else
        hr = ISAXContentHandler_endElement(
1730
                handler->handler,
1731
                uri, SysStringLen(uri),
1732
                local, SysStringLen(local),
1733
                element->qname, SysStringLen(element->qname));
1734

1735
    free_attribute_values(This);
1736
    This->attr_count = 0;
1737

1738 1739 1740
    if (sax_callback_failed(This, hr))
    {
        format_error_message_from_id(This, hr);
1741
        free_element_entry(element);
1742 1743
        return;
    }
1744

1745
    if (is_namespaces_enabled(This->saxreader))
1746
    {
1747
        int i = -1;
1748
        while (iterate_endprefix_index(This, element, &i) && saxreader_has_handler(This, SAXContentHandler))
1749 1750 1751
        {
            if (This->vbInterface)
                hr = IVBSAXContentHandler_endPrefixMapping(
1752
                        handler->vbhandler, &element->ns[i].prefix);
1753 1754
            else
                hr = ISAXContentHandler_endPrefixMapping(
1755
                        handler->handler, element->ns[i].prefix, SysStringLen(element->ns[i].prefix));
1756

1757 1758
            if (sax_callback_failed(This, hr)) break;
       }
1759

1760 1761 1762
       if (sax_callback_failed(This, hr))
           format_error_message_from_id(This, hr);
    }
1763

1764
    free_element_entry(element);
1765 1766
}

1767 1768 1769 1770 1771 1772
static void libxmlCharacters(
        void *ctx,
        const xmlChar *ch,
        int len)
{
    saxlocator *This = ctx;
1773
    BSTR Chars;
1774
    HRESULT hr;
1775
    xmlChar *cur, *end;
1776
    BOOL lastEvent = FALSE;
1777

1778
    if (!saxreader_has_handler(This, SAXContentHandler)) return;
1779

1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791
    update_position(This, FALSE);
    cur = (xmlChar*)This->pParserCtxt->input->cur;
    while(cur>=This->pParserCtxt->input->base && *cur!='>')
    {
        if(*cur=='\n' || (*cur=='\r' && *(cur+1)!='\n'))
            This->line--;
        cur--;
    }
    This->column = 1;
    for(; cur>=This->pParserCtxt->input->base && *cur!='\n' && *cur!='\r'; cur--)
        This->column++;

1792 1793 1794
    cur = (xmlChar*)ch;
    if(*(ch-1)=='\r') cur--;
    end = cur;
1795

1796
    while(1)
1797
    {
1798 1799
        while(end-ch<len && *end!='\r') end++;
        if(end-ch==len)
1800
        {
1801 1802
            lastEvent = TRUE;
        }
1803 1804 1805 1806 1807
        else
        {
            *end = '\n';
            end++;
        }
1808

1809
        if (This->saxreader->version >= MSXML4)
1810 1811
        {
            xmlChar *p;
1812

1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824
            for(p=cur; p!=end; p++)
            {
                if(*p=='\n')
                {
                    This->line++;
                    This->column = 1;
                }
                else
                {
                    This->column++;
                }
            }
1825 1826 1827 1828 1829

            if(!lastEvent)
                This->column = 0;
        }

1830
        Chars = pooled_bstr_from_xmlCharN(&This->saxreader->pool, cur, end-cur);
1831
        hr = saxreader_saxcharacters(This, Chars);
1832

1833
        if (sax_callback_failed(This, hr))
1834 1835 1836 1837 1838
        {
            format_error_message_from_id(This, hr);
            return;
        }

1839
        if (This->saxreader->version < MSXML4)
1840
            This->column += end-cur;
1841

1842 1843
        if(lastEvent)
            break;
1844

1845
        *(end-1) = '\r';
1846 1847 1848 1849
        if(*end == '\n')
        {
            end++;
            This->column++;
1850
        }
1851
        cur = end;
1852

1853
        if(end-ch == len) break;
1854 1855 1856
    }
}

1857 1858 1859 1860 1861
static void libxmlSetDocumentLocator(
        void *ctx,
        xmlSAXLocatorPtr loc)
{
    saxlocator *This = ctx;
1862
    struct saxcontenthandler_iface *handler = saxreader_get_contenthandler(This->saxreader);
1863
    HRESULT hr = S_OK;
1864

1865
    if (saxreader_has_handler(This, SAXContentHandler))
1866 1867
    {
        if(This->vbInterface)
1868
            hr = IVBSAXContentHandler_putref_documentLocator(handler->vbhandler,
1869
                    &This->IVBSAXLocator_iface);
1870
        else
1871
            hr = ISAXContentHandler_putDocumentLocator(handler->handler, &This->ISAXLocator_iface);
1872
    }
1873 1874

    if(FAILED(hr))
1875 1876 1877
        format_error_message_from_id(This, hr);
}

1878 1879 1880
static void libxmlComment(void *ctx, const xmlChar *value)
{
    saxlocator *This = ctx;
1881
    struct saxlexicalhandler_iface *handler = saxreader_get_lexicalhandler(This->saxreader);
1882 1883
    BSTR bValue;
    HRESULT hr;
1884
    const xmlChar *p = This->pParserCtxt->input->cur;
1885

1886 1887 1888 1889 1890 1891 1892 1893
    update_position(This, FALSE);
    while(p-4>=This->pParserCtxt->input->base
            && memcmp(p-4, "<!--", sizeof(char[4])))
    {
        if(*p=='\n' || (*p=='\r' && *(p+1)!='\n'))
            This->line--;
        p--;
    }
1894

1895 1896 1897
    This->column = 0;
    for(; p>=This->pParserCtxt->input->base && *p!='\n' && *p!='\r'; p--)
        This->column++;
1898

1899
    if (!saxreader_has_handler(This, SAXLexicalHandler)) return;
1900

1901
    bValue = pooled_bstr_from_xmlChar(&This->saxreader->pool, value);
1902

1903 1904
    if (This->vbInterface)
        hr = IVBSAXLexicalHandler_comment(handler->vbhandler, &bValue);
1905
    else
1906
        hr = ISAXLexicalHandler_comment(handler->handler, bValue, SysStringLen(bValue));
1907 1908 1909 1910 1911

    if(FAILED(hr))
        format_error_message_from_id(This, hr);
}

1912
static void libxmlFatalError(void *ctx, const char *msg, ...)
1913 1914
{
    saxlocator *This = ctx;
1915
    struct saxerrorhandler_iface *handler = saxreader_get_errorhandler(This->saxreader);
1916
    char message[1024];
1917
    WCHAR *error;
1918 1919 1920
    DWORD len;
    va_list args;

1921 1922
    if(This->ret != S_OK) {
        xmlStopParser(This->pParserCtxt);
1923
        return;
1924
    }
1925

1926 1927 1928 1929
    va_start(args, msg);
    vsprintf(message, msg, args);
    va_end(args);

1930
    len = MultiByteToWideChar(CP_UNIXCP, 0, message, -1, NULL, 0);
1931 1932 1933 1934 1935 1936
    error = heap_alloc(sizeof(WCHAR)*len);
    if(error)
    {
        MultiByteToWideChar(CP_UNIXCP, 0, message, -1, error, len);
        TRACE("fatal error for %p: %s\n", This, debugstr_w(error));
    }
1937

1938
    if (!saxreader_has_handler(This, SAXErrorHandler))
1939 1940 1941 1942 1943 1944 1945 1946 1947
    {
        xmlStopParser(This->pParserCtxt);
        This->ret = E_FAIL;
        heap_free(error);
        return;
    }

    FIXME("Error handling is not compatible.\n");

1948 1949
    if(This->vbInterface)
    {
1950
        BSTR bstrError = SysAllocString(error);
1951
        IVBSAXErrorHandler_fatalError(handler->vbhandler, &This->IVBSAXLocator_iface,
1952
                &bstrError, E_FAIL);
1953
        SysFreeString(bstrError);
1954 1955
    }
    else
1956
        ISAXErrorHandler_fatalError(handler->handler, &This->ISAXLocator_iface, error, E_FAIL);
1957

1958
    heap_free(error);
1959 1960 1961

    xmlStopParser(This->pParserCtxt);
    This->ret = E_FAIL;
1962 1963
}

1964 1965 1966 1967 1968 1969
/* The only reason this helper exists is that CDATA section are reported by chunks,
   newlines are used as delimiter. More than that, reader even alters input data before reporting.

   This helper should be called for substring with trailing newlines.
*/
static BSTR saxreader_get_cdata_chunk(const xmlChar *str, int len)
1970
{
1971 1972
    BSTR bstr = bstr_from_xmlCharN(str, len), ret;
    WCHAR *ptr;
1973

1974 1975 1976 1977 1978
    ptr = bstr + len - 1;
    while ((*ptr == '\r' || *ptr == '\n') && ptr >= bstr)
        ptr--;

    while (*++ptr)
1979
    {
1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995
        /* replace returns as:

           - "\r<char>" -> "\n<char>"
           - "\r\r" -> "\r"
           - "\r\n" -> "\n"
        */
        if (*ptr == '\r')
        {
            if (*(ptr+1) == '\r' || *(ptr+1) == '\n')
            {
                /* shift tail */
                memmove(ptr, ptr+1, len-- - (ptr-bstr));
            }
            else
                *ptr = '\n';
        }
1996
    }
1997

1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
    ret = SysAllocStringLen(bstr, len);
    SysFreeString(bstr);
    return ret;
}

static void libxml_cdatablock(void *ctx, const xmlChar *value, int len)
{
    const xmlChar *start, *end;
    saxlocator *locator = ctx;
    struct saxlexicalhandler_iface *lexical = saxreader_get_lexicalhandler(locator->saxreader);
    HRESULT hr = S_OK;
    BSTR chars;
    int i;

    update_position(locator, FALSE);
    if (saxreader_has_handler(locator, SAXLexicalHandler))
2014
    {
2015
       if (locator->vbInterface)
2016
           hr = IVBSAXLexicalHandler_startCDATA(lexical->vbhandler);
2017
       else
2018
           hr = ISAXLexicalHandler_startCDATA(lexical->handler);
2019
    }
2020 2021

    if(FAILED(hr))
2022
    {
2023
        format_error_message_from_id(locator, hr);
2024 2025
        return;
    }
2026

2027 2028 2029
    start = value;
    end = NULL;
    i = 0;
2030

2031
    while (i < len)
2032
    {
2033 2034
        /* scan for newlines */
        if (value[i] == '\r' || value[i] == '\n')
2035
        {
2036 2037 2038 2039 2040 2041 2042
            /* skip newlines/linefeeds */
            while (i < len)
            {
                if (value[i] != '\r' && value[i] != '\n') break;
                    i++;
            }
            end = &value[i];
2043

2044 2045 2046 2047 2048
            /* report */
            chars = saxreader_get_cdata_chunk(start, end-start);
            TRACE("(chunk %s)\n", debugstr_w(chars));
            hr = saxreader_saxcharacters(locator, chars);
            SysFreeString(chars);
2049

2050 2051
            start = &value[i];
            end = NULL;
2052
        }
2053 2054 2055
        i++;
        locator->column++;
    }
2056

2057 2058 2059 2060 2061 2062 2063 2064
    /* no newline chars (or last chunk) report as a whole */
    if (!end && start == value)
    {
        /* report */
        chars = bstr_from_xmlCharN(start, len-(start-value));
        TRACE("(%s)\n", debugstr_w(chars));
        hr = saxreader_saxcharacters(locator, chars);
        SysFreeString(chars);
2065 2066
    }

2067
    if (saxreader_has_handler(locator, SAXLexicalHandler))
2068
    {
2069
        if (locator->vbInterface)
2070
            hr = IVBSAXLexicalHandler_endCDATA(lexical->vbhandler);
2071
        else
2072
            hr = ISAXLexicalHandler_endCDATA(lexical->handler);
2073
    }
2074 2075

    if(FAILED(hr))
2076
        format_error_message_from_id(locator, hr);
2077 2078
}

2079 2080 2081 2082 2083 2084
static xmlParserInputPtr libxmlresolveentity(void *ctx, const xmlChar *publicid, const xmlChar *systemid)
{
    FIXME("entity resolving not implemented, %s, %s\n", publicid, systemid);
    return xmlSAX2ResolveEntity(ctx, publicid, systemid);
}

2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100
/*** IVBSAXLocator interface ***/
/*** IUnknown methods ***/
static HRESULT WINAPI ivbsaxlocator_QueryInterface(IVBSAXLocator* iface, REFIID riid, void **ppvObject)
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );

    TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject);

    *ppvObject = NULL;

    if ( IsEqualGUID( riid, &IID_IUnknown ) ||
            IsEqualGUID( riid, &IID_IDispatch) ||
            IsEqualGUID( riid, &IID_IVBSAXLocator ))
    {
        *ppvObject = iface;
    }
2101 2102 2103 2104
    else if ( IsEqualGUID( riid, &IID_IVBSAXAttributes ))
    {
        *ppvObject = &This->IVBSAXAttributes_iface;
    }
2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119
    else
    {
        FIXME("interface %s not implemented\n", debugstr_guid(riid));
        return E_NOINTERFACE;
    }

    IVBSAXLocator_AddRef( iface );

    return S_OK;
}

static ULONG WINAPI ivbsaxlocator_AddRef(IVBSAXLocator* iface)
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );
    TRACE("%p\n", This );
2120
    return ISAXLocator_AddRef(&This->ISAXLocator_iface);
2121 2122
}

2123
static ULONG WINAPI ivbsaxlocator_Release(IVBSAXLocator* iface)
2124 2125
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );
2126
    return ISAXLocator_Release(&This->ISAXLocator_iface);
2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142
}

/*** IDispatch methods ***/
static HRESULT WINAPI ivbsaxlocator_GetTypeInfoCount( IVBSAXLocator *iface, UINT* pctinfo )
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );

    TRACE("(%p)->(%p)\n", This, pctinfo);

    *pctinfo = 1;

    return S_OK;
}

static HRESULT WINAPI ivbsaxlocator_GetTypeInfo(
    IVBSAXLocator *iface,
2143
    UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
2144 2145 2146
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );

2147 2148
    TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);

2149
    return get_typeinfo(IVBSAXLocator_tid, ppTInfo);
2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171
}

static HRESULT WINAPI ivbsaxlocator_GetIDsOfNames(
    IVBSAXLocator *iface,
    REFIID riid,
    LPOLESTR* rgszNames,
    UINT cNames,
    LCID lcid,
    DISPID* rgDispId)
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );
    ITypeInfo *typeinfo;
    HRESULT hr;

    TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
          lcid, rgDispId);

    if(!rgszNames || cNames == 0 || !rgDispId)
        return E_INVALIDARG;

    hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo);
    if(SUCCEEDED(hr))
2172
    {
2173
        hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
2174 2175
        ITypeInfo_Release(typeinfo);
    }
2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199

    return hr;
}

static HRESULT WINAPI ivbsaxlocator_Invoke(
    IVBSAXLocator *iface,
    DISPID dispIdMember,
    REFIID riid,
    LCID lcid,
    WORD wFlags,
    DISPPARAMS* pDispParams,
    VARIANT* pVarResult,
    EXCEPINFO* pExcepInfo,
    UINT* puArgErr)
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );
    ITypeInfo *typeinfo;
    HRESULT hr;

    TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
          lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);

    hr = get_typeinfo(IVBSAXLocator_tid, &typeinfo);
    if(SUCCEEDED(hr))
2200
    {
2201 2202
        hr = ITypeInfo_Invoke(typeinfo, &This->IVBSAXLocator_iface, dispIdMember, wFlags,
                pDispParams, pVarResult, pExcepInfo, puArgErr);
2203 2204
        ITypeInfo_Release(typeinfo);
    }
2205 2206 2207 2208 2209 2210 2211 2212 2213 2214

    return hr;
}

/*** IVBSAXLocator methods ***/
static HRESULT WINAPI ivbsaxlocator_get_columnNumber(
        IVBSAXLocator* iface,
        int *pnColumn)
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );
2215
    return ISAXLocator_getColumnNumber(&This->ISAXLocator_iface, pnColumn);
2216 2217 2218 2219 2220 2221 2222
}

static HRESULT WINAPI ivbsaxlocator_get_lineNumber(
        IVBSAXLocator* iface,
        int *pnLine)
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );
2223
    return ISAXLocator_getLineNumber(&This->ISAXLocator_iface, pnLine);
2224 2225
}

2226
static HRESULT WINAPI ivbsaxlocator_get_publicId(IVBSAXLocator* iface, BSTR *ret)
2227 2228
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );
2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242
    const WCHAR *publicidW;
    HRESULT hr;

    TRACE("(%p)->(%p)\n", This, ret);

    if (!ret)
        return E_POINTER;

    *ret = NULL;
    hr = ISAXLocator_getPublicId(&This->ISAXLocator_iface, &publicidW);
    if (FAILED(hr))
        return hr;

    return return_bstr(publicidW, ret);
2243 2244
}

2245
static HRESULT WINAPI ivbsaxlocator_get_systemId(IVBSAXLocator* iface, BSTR *ret)
2246 2247
{
    saxlocator *This = impl_from_IVBSAXLocator( iface );
2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261
    const WCHAR *systemidW;
    HRESULT hr;

    TRACE("(%p)->(%p)\n", This, ret);

    if (!ret)
        return E_POINTER;

    *ret = NULL;
    hr = ISAXLocator_getSystemId(&This->ISAXLocator_iface, &systemidW);
    if (FAILED(hr))
        return hr;

    return return_bstr(systemidW, ret);
2262 2263
}

2264
static const struct IVBSAXLocatorVtbl VBSAXLocatorVtbl =
2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278
{
    ivbsaxlocator_QueryInterface,
    ivbsaxlocator_AddRef,
    ivbsaxlocator_Release,
    ivbsaxlocator_GetTypeInfoCount,
    ivbsaxlocator_GetTypeInfo,
    ivbsaxlocator_GetIDsOfNames,
    ivbsaxlocator_Invoke,
    ivbsaxlocator_get_columnNumber,
    ivbsaxlocator_get_lineNumber,
    ivbsaxlocator_get_publicId,
    ivbsaxlocator_get_systemId
};

2279 2280 2281 2282 2283 2284
/*** ISAXLocator interface ***/
/*** IUnknown methods ***/
static HRESULT WINAPI isaxlocator_QueryInterface(ISAXLocator* iface, REFIID riid, void **ppvObject)
{
    saxlocator *This = impl_from_ISAXLocator( iface );

2285
    TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
2286 2287 2288 2289 2290 2291 2292 2293

    *ppvObject = NULL;

    if ( IsEqualGUID( riid, &IID_IUnknown ) ||
            IsEqualGUID( riid, &IID_ISAXLocator ))
    {
        *ppvObject = iface;
    }
2294 2295 2296 2297
    else if ( IsEqualGUID( riid, &IID_ISAXAttributes ))
    {
        *ppvObject = &This->ISAXAttributes_iface;
    }
2298 2299
    else
    {
2300
        WARN("interface %s not implemented\n", debugstr_guid(riid));
2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311
        return E_NOINTERFACE;
    }

    ISAXLocator_AddRef( iface );

    return S_OK;
}

static ULONG WINAPI isaxlocator_AddRef(ISAXLocator* iface)
{
    saxlocator *This = impl_from_ISAXLocator( iface );
2312 2313 2314
    ULONG ref = InterlockedIncrement( &This->ref );
    TRACE("(%p)->(%d)\n", This, ref);
    return ref;
2315 2316 2317 2318 2319 2320
}

static ULONG WINAPI isaxlocator_Release(
        ISAXLocator* iface)
{
    saxlocator *This = impl_from_ISAXLocator( iface );
2321
    LONG ref = InterlockedDecrement( &This->ref );
2322

2323
    TRACE("(%p)->(%d)\n", This, ref );
2324

2325
    if (ref == 0)
2326
    {
2327
        element_entry *element, *element2;
2328
        int index;
2329

2330 2331
        SysFreeString(This->publicId);
        SysFreeString(This->systemId);
2332
        SysFreeString(This->namespaceUri);
2333

2334
        for(index = 0; index < This->attr_alloc_count; index++)
2335 2336 2337 2338 2339 2340
        {
            SysFreeString(This->attributes[index].szLocalname);
            SysFreeString(This->attributes[index].szValue);
            SysFreeString(This->attributes[index].szQName);
        }
        heap_free(This->attributes);
2341

2342 2343 2344 2345 2346 2347 2348
        /* element stack */
        LIST_FOR_EACH_ENTRY_SAFE(element, element2, &This->elements, element_entry, entry)
        {
            list_remove(&element->entry);
            free_element_entry(element);
        }

2349
        ISAXXMLReader_Release(&This->saxreader->ISAXXMLReader_iface);
2350
        heap_free( This );
2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362
    }

    return ref;
}

/*** ISAXLocator methods ***/
static HRESULT WINAPI isaxlocator_getColumnNumber(
        ISAXLocator* iface,
        int *pnColumn)
{
    saxlocator *This = impl_from_ISAXLocator( iface );

2363
    *pnColumn = This->column;
2364
    return S_OK;
2365 2366 2367 2368 2369 2370 2371 2372
}

static HRESULT WINAPI isaxlocator_getLineNumber(
        ISAXLocator* iface,
        int *pnLine)
{
    saxlocator *This = impl_from_ISAXLocator( iface );

2373
    *pnLine = This->line;
2374
    return S_OK;
2375 2376 2377 2378 2379 2380
}

static HRESULT WINAPI isaxlocator_getPublicId(
        ISAXLocator* iface,
        const WCHAR ** ppwchPublicId)
{
2381
    BSTR publicId;
2382 2383
    saxlocator *This = impl_from_ISAXLocator( iface );

2384
    SysFreeString(This->publicId);
2385 2386 2387

    publicId = bstr_from_xmlChar(xmlSAX2GetPublicId(This->pParserCtxt));
    if(SysStringLen(publicId))
2388
        This->publicId = publicId;
2389 2390 2391 2392 2393 2394 2395 2396
    else
    {
        SysFreeString(publicId);
        This->publicId = NULL;
    }

    *ppwchPublicId = This->publicId;
    return S_OK;
2397 2398 2399 2400 2401 2402
}

static HRESULT WINAPI isaxlocator_getSystemId(
        ISAXLocator* iface,
        const WCHAR ** ppwchSystemId)
{
2403
    BSTR systemId;
2404 2405
    saxlocator *This = impl_from_ISAXLocator( iface );

2406
    SysFreeString(This->systemId);
2407 2408 2409

    systemId = bstr_from_xmlChar(xmlSAX2GetSystemId(This->pParserCtxt));
    if(SysStringLen(systemId))
2410
        This->systemId = systemId;
2411 2412 2413 2414 2415 2416 2417 2418
    else
    {
        SysFreeString(systemId);
        This->systemId = NULL;
    }

    *ppwchSystemId = This->systemId;
    return S_OK;
2419 2420
}

2421
static const struct ISAXLocatorVtbl SAXLocatorVtbl =
2422 2423 2424 2425 2426 2427 2428 2429 2430 2431
{
    isaxlocator_QueryInterface,
    isaxlocator_AddRef,
    isaxlocator_Release,
    isaxlocator_getColumnNumber,
    isaxlocator_getLineNumber,
    isaxlocator_getPublicId,
    isaxlocator_getSystemId
};

2432
static HRESULT SAXLocator_create(saxreader *reader, saxlocator **ppsaxlocator, BOOL vbInterface)
2433
{
2434 2435 2436
    static const WCHAR w3xmlns[] = { 'h','t','t','p',':','/','/', 'w','w','w','.','w','3','.',
        'o','r','g','/','2','0','0','0','/','x','m','l','n','s','/',0 };

2437 2438
    saxlocator *locator;

2439
    locator = heap_alloc( sizeof (*locator) );
2440 2441 2442
    if( !locator )
        return E_OUTOFMEMORY;

2443 2444
    locator->IVBSAXLocator_iface.lpVtbl = &VBSAXLocatorVtbl;
    locator->ISAXLocator_iface.lpVtbl = &SAXLocatorVtbl;
2445 2446
    locator->IVBSAXAttributes_iface.lpVtbl = &ivbsaxattributes_vtbl;
    locator->ISAXAttributes_iface.lpVtbl = &isaxattributes_vtbl;
2447
    locator->ref = 1;
2448
    locator->vbInterface = vbInterface;
2449 2450

    locator->saxreader = reader;
2451
    ISAXXMLReader_AddRef(&reader->ISAXXMLReader_iface);
2452

2453
    locator->pParserCtxt = NULL;
2454
    locator->publicId = NULL;
2455
    locator->systemId = NULL;
2456
    locator->line = reader->version < MSXML4 ? 0 : 1;
2457
    locator->column = 0;
2458
    locator->ret = S_OK;
2459
    if (locator->saxreader->version >= MSXML6)
2460 2461 2462
        locator->namespaceUri = SysAllocString(w3xmlns);
    else
        locator->namespaceUri = SysAllocStringLen(NULL, 0);
2463
    if(!locator->namespaceUri)
2464 2465
    {
        ISAXXMLReader_Release(&reader->ISAXXMLReader_iface);
2466 2467 2468 2469
        heap_free(locator);
        return E_OUTOFMEMORY;
    }

2470 2471 2472
    locator->attr_alloc_count = 8;
    locator->attr_count = 0;
    locator->attributes = heap_alloc_zero(sizeof(struct _attributes)*locator->attr_alloc_count);
2473 2474 2475 2476
    if(!locator->attributes)
    {
        ISAXXMLReader_Release(&reader->ISAXXMLReader_iface);
        SysFreeString(locator->namespaceUri);
2477 2478 2479 2480
        heap_free(locator);
        return E_OUTOFMEMORY;
    }

2481 2482
    list_init(&locator->elements);

2483 2484 2485 2486 2487 2488 2489
    *ppsaxlocator = locator;

    TRACE("returning %p\n", *ppsaxlocator);

    return S_OK;
}

2490 2491 2492
/*** SAXXMLReader internal functions ***/
static HRESULT internal_parseBuffer(saxreader *This, const char *buffer, int size, BOOL vbInterface)
{
2493 2494
    xmlCharEncoding encoding = XML_CHAR_ENCODING_NONE;
    xmlChar *enc_name = NULL;
2495 2496 2497
    saxlocator *locator;
    HRESULT hr;

2498 2499
    TRACE("(%p)->(%p %d)\n", This, buffer, size);

2500
    hr = SAXLocator_create(This, &locator, vbInterface);
2501
    if (FAILED(hr))
2502
        return hr;
2503

2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519
    if (size >= 4)
    {
        const unsigned char *buff = (unsigned char*)buffer;

        encoding = xmlDetectCharEncoding((xmlChar*)buffer, 4);
        enc_name = (xmlChar*)xmlGetCharEncodingName(encoding);
        TRACE("detected encoding: %s\n", enc_name);
        /* skip BOM, parser won't switch encodings and so won't skip it on its own */
        if ((encoding == XML_CHAR_ENCODING_UTF8) &&
            buff[0] == 0xEF && buff[1] == 0xBB && buff[2] == 0xBF)
        {
            buffer += 3;
            size -= 3;
        }
    }

2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535
    /* if libxml2 detection failed try to guess */
    if (encoding == XML_CHAR_ENCODING_NONE)
    {
        const WCHAR *ptr = (WCHAR*)buffer;
        /* xml declaration with possibly specfied encoding will be still handled by parser */
        if ((size >= 2) && *ptr == '<' && ptr[1] != '?')
        {
            enc_name = (xmlChar*)xmlGetCharEncodingName(XML_CHAR_ENCODING_UTF16LE);
            encoding = XML_CHAR_ENCODING_UTF16LE;
        }
    }
    else if (encoding == XML_CHAR_ENCODING_UTF8)
        enc_name = (xmlChar*)xmlGetCharEncodingName(encoding);
    else
        enc_name = NULL;

2536
    locator->pParserCtxt = xmlCreateMemoryParserCtxt(buffer, size);
2537
    if (!locator->pParserCtxt)
2538
    {
2539
        ISAXLocator_Release(&locator->ISAXLocator_iface);
2540 2541 2542
        return E_FAIL;
    }

2543 2544
    if (enc_name)
    {
2545
        locator->pParserCtxt->encoding = xmlStrdup(enc_name);
2546 2547 2548 2549 2550
        if (encoding == XML_CHAR_ENCODING_UTF16LE) {
            TRACE("switching to %s\n", enc_name);
            xmlSwitchEncoding(locator->pParserCtxt, encoding);
        }
    }
2551

2552
    xmlFree(locator->pParserCtxt->sax);
2553 2554 2555
    locator->pParserCtxt->sax = &locator->saxreader->sax;
    locator->pParserCtxt->userData = locator;

2556
    This->isParsing = TRUE;
2557
    if(xmlParseDocument(locator->pParserCtxt) == -1 && locator->ret == S_OK)
2558 2559 2560
        hr = E_FAIL;
    else
        hr = locator->ret;
2561
    This->isParsing = FALSE;
2562 2563 2564 2565 2566 2567 2568 2569

    if(locator->pParserCtxt)
    {
        locator->pParserCtxt->sax = NULL;
        xmlFreeParserCtxt(locator->pParserCtxt);
        locator->pParserCtxt = NULL;
    }

2570
    ISAXLocator_Release(&locator->ISAXLocator_iface);
2571
    return hr;
2572 2573
}

2574
static HRESULT internal_parseStream(saxreader *This, ISequentialStream *stream, BOOL vbInterface)
2575 2576 2577 2578
{
    saxlocator *locator;
    HRESULT hr;
    ULONG dataRead;
2579
    char data[2048];
2580
    int ret;
2581

2582
    dataRead = 0;
2583
    hr = ISequentialStream_Read(stream, data, sizeof(data), &dataRead);
2584
    if(FAILED(hr)) return hr;
2585 2586

    hr = SAXLocator_create(This, &locator, vbInterface);
2587
    if(FAILED(hr)) return hr;
2588 2589 2590 2591 2592 2593

    locator->pParserCtxt = xmlCreatePushParserCtxt(
            &locator->saxreader->sax, locator,
            data, dataRead, NULL);
    if(!locator->pParserCtxt)
    {
2594
        ISAXLocator_Release(&locator->ISAXLocator_iface);
2595 2596 2597
        return E_FAIL;
    }

2598
    This->isParsing = TRUE;
2599

2600 2601 2602 2603 2604 2605 2606 2607 2608 2609
    do {
        dataRead = 0;
        hr = ISequentialStream_Read(stream, data, sizeof(data), &dataRead);
        if (FAILED(hr) || !dataRead) break;

        ret = xmlParseChunk(locator->pParserCtxt, data, dataRead, 0);
        hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret;
    }while(hr == S_OK);

    if(SUCCEEDED(hr))
2610 2611
    {
        ret = xmlParseChunk(locator->pParserCtxt, data, 0, 1);
2612
        hr = ret!=XML_ERR_OK && locator->ret==S_OK ? E_FAIL : locator->ret;
2613
    }
2614

2615

2616
    This->isParsing = FALSE;
2617 2618 2619

    xmlFreeParserCtxt(locator->pParserCtxt);
    locator->pParserCtxt = NULL;
2620
    ISAXLocator_Release(&locator->ISAXLocator_iface);
2621 2622 2623
    return hr;
}

2624
static HRESULT internal_parse(
2625 2626 2627 2628 2629 2630
        saxreader* This,
        VARIANT varInput,
        BOOL vbInterface)
{
    HRESULT hr;

2631
    TRACE("(%p)->(%s)\n", This, debugstr_variant(&varInput));
2632

2633 2634 2635
    /* Dispose of the BSTRs in the pool from a prior run, if any. */
    free_bstr_pool(&This->pool);

2636 2637 2638
    switch(V_VT(&varInput))
    {
        case VT_BSTR:
2639 2640 2641 2642
        case VT_BSTR|VT_BYREF:
        {
            BSTR str = V_ISBYREF(&varInput) ? *V_BSTRREF(&varInput) : V_BSTR(&varInput);
            hr = internal_parseBuffer(This, (const char*)str, strlenW(str)*sizeof(WCHAR), vbInterface);
2643
            break;
2644
        }
2645 2646 2647 2648 2649 2650 2651 2652 2653 2654
        case VT_ARRAY|VT_UI1: {
            void *pSAData;
            LONG lBound, uBound;
            ULONG dataRead;

            hr = SafeArrayGetLBound(V_ARRAY(&varInput), 1, &lBound);
            if(hr != S_OK) break;
            hr = SafeArrayGetUBound(V_ARRAY(&varInput), 1, &uBound);
            if(hr != S_OK) break;
            dataRead = (uBound-lBound)*SafeArrayGetElemsize(V_ARRAY(&varInput));
2655
            hr = SafeArrayAccessData(V_ARRAY(&varInput), &pSAData);
2656 2657 2658 2659 2660 2661 2662 2663
            if(hr != S_OK) break;
            hr = internal_parseBuffer(This, pSAData, dataRead, vbInterface);
            SafeArrayUnaccessData(V_ARRAY(&varInput));
            break;
        }
        case VT_UNKNOWN:
        case VT_DISPATCH: {
            IPersistStream *persistStream;
2664
            ISequentialStream *stream = NULL;
2665 2666
            IXMLDOMDocument *xmlDoc;

2667 2668 2669 2670 2671 2672 2673 2674 2675
            if(IUnknown_QueryInterface(V_UNKNOWN(&varInput),
                        &IID_IXMLDOMDocument, (void**)&xmlDoc) == S_OK)
            {
                BSTR bstrData;

                IXMLDOMDocument_get_xml(xmlDoc, &bstrData);
                hr = internal_parseBuffer(This, (const char*)bstrData,
                        SysStringByteLen(bstrData), vbInterface);
                IXMLDOMDocument_Release(xmlDoc);
2676
                SysFreeString(bstrData);
2677 2678
                break;
            }
2679

2680 2681 2682
            if(IUnknown_QueryInterface(V_UNKNOWN(&varInput),
                        &IID_IPersistStream, (void**)&persistStream) == S_OK)
            {
2683 2684 2685
                IStream *stream_copy;

                hr = CreateStreamOnHGlobal(NULL, TRUE, &stream_copy);
2686 2687 2688 2689 2690 2691
                if(hr != S_OK)
                {
                    IPersistStream_Release(persistStream);
                    return hr;
                }

2692
                hr = IPersistStream_Save(persistStream, stream_copy, TRUE);
2693
                IPersistStream_Release(persistStream);
2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706
                if(hr == S_OK)
                    IStream_QueryInterface(stream_copy, &IID_ISequentialStream, (void**)&stream);

                IStream_Release(stream_copy);
            }

            /* try base interface first */
            if(!stream)
            {
                IUnknown_QueryInterface(V_UNKNOWN(&varInput), &IID_ISequentialStream, (void**)&stream);
                if (!stream)
                    /* this should never happen if IStream is implemented properly, but just in case */
                    IUnknown_QueryInterface(V_UNKNOWN(&varInput), &IID_IStream, (void**)&stream);
2707
            }
2708

2709
            if(stream)
2710
            {
2711
                hr = internal_parseStream(This, stream, vbInterface);
2712
                ISequentialStream_Release(stream);
2713
            }
2714 2715 2716 2717 2718 2719 2720
            else
            {
                WARN("IUnknown* input doesn't support any of expected interfaces\n");
                hr = E_INVALIDARG;
            }

            break;
2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743
        }
        default:
            WARN("vt %d not implemented\n", V_VT(&varInput));
            hr = E_INVALIDARG;
    }

    return hr;
}

static HRESULT internal_vbonDataAvailable(void *obj, char *ptr, DWORD len)
{
    saxreader *This = obj;

    return internal_parseBuffer(This, ptr, len, TRUE);
}

static HRESULT internal_onDataAvailable(void *obj, char *ptr, DWORD len)
{
    saxreader *This = obj;

    return internal_parseBuffer(This, ptr, len, FALSE);
}

2744
static HRESULT internal_parseURL(
2745 2746 2747 2748
        saxreader* This,
        const WCHAR *url,
        BOOL vbInterface)
{
2749
    IMoniker *mon;
2750 2751 2752 2753 2754
    bsc_t *bsc;
    HRESULT hr;

    TRACE("(%p)->(%s)\n", This, debugstr_w(url));

2755 2756 2757 2758 2759 2760 2761
    hr = create_moniker_from_url(url, &mon);
    if(FAILED(hr))
        return hr;

    if(vbInterface) hr = bind_url(mon, internal_vbonDataAvailable, This, &bsc);
    else hr = bind_url(mon, internal_onDataAvailable, This, &bsc);
    IMoniker_Release(mon);
2762 2763 2764 2765

    if(FAILED(hr))
        return hr;

2766
    return detach_bsc(bsc);
2767 2768
}

2769
static HRESULT saxreader_put_handler_from_variant(saxreader *This, enum saxhandler_type type, const VARIANT *v, BOOL vb)
2770
{
2771
    const IID *riid;
2772

2773 2774
    if (V_VT(v) == VT_EMPTY)
        return saxreader_put_handler(This, type, NULL, vb);
2775

2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787
    switch (type)
    {
    case SAXDeclHandler:
        riid = vb ? &IID_IVBSAXDeclHandler : &IID_ISAXDeclHandler;
        break;
    case SAXLexicalHandler:
        riid = vb ? &IID_IVBSAXLexicalHandler : &IID_ISAXLexicalHandler;
        break;
    default:
        ERR("wrong handler type %d\n", type);
        return E_FAIL;
    }
2788

2789 2790 2791 2792 2793 2794
    switch (V_VT(v))
    {
    case VT_DISPATCH:
    case VT_UNKNOWN:
    {
        IUnknown *handler = NULL;
2795

2796 2797 2798 2799
        if (V_UNKNOWN(v))
        {
            HRESULT hr = IUnknown_QueryInterface(V_UNKNOWN(v), riid, (void**)&handler);
            if (FAILED(hr)) return hr;
2800
        }
2801

2802 2803 2804 2805 2806 2807 2808
        saxreader_put_handler(This, type, handler, vb);
        if (handler) IUnknown_Release(handler);
        break;
    }
    default:
        ERR("value type %d not supported\n", V_VT(v));
        return E_INVALIDARG;
2809 2810
    }

2811 2812
    return S_OK;
}
2813

2814 2815 2816 2817 2818 2819 2820
static HRESULT internal_putProperty(
    saxreader* This,
    const WCHAR *prop,
    VARIANT value,
    BOOL vbInterface)
{
    VARIANT *v;
2821

2822
    TRACE("(%p)->(%s %s)\n", This, debugstr_w(prop), debugstr_variant(&value));
2823

2824
    if (This->isParsing) return E_FAIL;
2825

2826 2827 2828
    v = V_VT(&value) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(&value) : &value;
    if(!memcmp(prop, PropertyDeclHandlerW, sizeof(PropertyDeclHandlerW)))
        return saxreader_put_handler_from_variant(This, SAXDeclHandler, v, vbInterface);
2829

2830 2831
    if(!memcmp(prop, PropertyLexicalHandlerW, sizeof(PropertyLexicalHandlerW)))
        return saxreader_put_handler_from_variant(This, SAXLexicalHandler, v, vbInterface);
2832

2833 2834
    if(!memcmp(prop, PropertyMaxXMLSizeW, sizeof(PropertyMaxXMLSizeW)))
    {
2835 2836
        if (V_VT(v) == VT_I4 && V_I4(v) == 0) return S_OK;
        FIXME("(%p)->(%s): max-xml-size unsupported\n", This, debugstr_variant(v));
2837 2838 2839
        return E_NOTIMPL;
    }

2840 2841
    if(!memcmp(prop, PropertyMaxElementDepthW, sizeof(PropertyMaxElementDepthW)))
    {
2842 2843
        if (V_VT(v) == VT_I4 && V_I4(v) == 0) return S_OK;
        FIXME("(%p)->(%s): max-element-depth unsupported\n", This, debugstr_variant(v));
2844 2845 2846
        return E_NOTIMPL;
    }

2847
    FIXME("(%p)->(%s:%s): unsupported property\n", This, debugstr_w(prop), debugstr_variant(v));
2848

2849
    if(!memcmp(prop, PropertyCharsetW, sizeof(PropertyCharsetW)))
2850 2851
        return E_NOTIMPL;

2852
    if(!memcmp(prop, PropertyDomNodeW, sizeof(PropertyDomNodeW)))
2853 2854
        return E_FAIL;

2855
    if(!memcmp(prop, PropertyInputSourceW, sizeof(PropertyInputSourceW)))
2856 2857
        return E_NOTIMPL;

2858
    if(!memcmp(prop, PropertySchemaDeclHandlerW, sizeof(PropertySchemaDeclHandlerW)))
2859 2860
        return E_NOTIMPL;

2861
    if(!memcmp(prop, PropertyXMLDeclEncodingW, sizeof(PropertyXMLDeclEncodingW)))
2862 2863
        return E_FAIL;

2864
    if(!memcmp(prop, PropertyXMLDeclStandaloneW, sizeof(PropertyXMLDeclStandaloneW)))
2865 2866
        return E_FAIL;

2867
    if(!memcmp(prop, PropertyXMLDeclVersionW, sizeof(PropertyXMLDeclVersionW)))
2868 2869 2870 2871 2872
        return E_FAIL;

    return E_INVALIDARG;
}

2873 2874 2875 2876 2877 2878 2879 2880 2881
static HRESULT internal_getProperty(const saxreader* This, const WCHAR *prop, VARIANT *value, BOOL vb)
{
    TRACE("(%p)->(%s)\n", This, debugstr_w(prop));

    if (!value) return E_POINTER;

    if (!memcmp(PropertyLexicalHandlerW, prop, sizeof(PropertyLexicalHandlerW)))
    {
        V_VT(value) = VT_UNKNOWN;
2882
        saxreader_get_handler(This, SAXLexicalHandler, vb, (void**)&V_UNKNOWN(value));
2883 2884 2885 2886 2887 2888
        return S_OK;
    }

    if (!memcmp(PropertyDeclHandlerW, prop, sizeof(PropertyDeclHandlerW)))
    {
        V_VT(value) = VT_UNKNOWN;
2889
        saxreader_get_handler(This, SAXDeclHandler, vb, (void**)&V_UNKNOWN(value));
2890 2891 2892
        return S_OK;
    }

2893 2894 2895 2896 2897 2898 2899
    if (!memcmp(PropertyXmlDeclVersionW, prop, sizeof(PropertyXmlDeclVersionW)))
    {
        V_VT(value) = VT_BSTR;
        V_BSTR(value) = SysAllocString(This->xmldecl_version);
        return S_OK;
    }

2900 2901 2902 2903 2904
    FIXME("(%p)->(%s) unsupported property\n", This, debugstr_w(prop));

    return E_NOTIMPL;
}

2905
/*** IVBSAXXMLReader interface ***/
2906 2907 2908 2909 2910
/*** IUnknown methods ***/
static HRESULT WINAPI saxxmlreader_QueryInterface(IVBSAXXMLReader* iface, REFIID riid, void **ppvObject)
{
    saxreader *This = impl_from_IVBSAXXMLReader( iface );

2911
    TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
2912 2913 2914 2915 2916 2917 2918 2919 2920

    *ppvObject = NULL;

    if ( IsEqualGUID( riid, &IID_IUnknown ) ||
         IsEqualGUID( riid, &IID_IDispatch ) ||
         IsEqualGUID( riid, &IID_IVBSAXXMLReader ))
    {
        *ppvObject = iface;
    }
2921 2922
    else if( IsEqualGUID( riid, &IID_ISAXXMLReader ))
    {
2923
        *ppvObject = &This->ISAXXMLReader_iface;
2924
    }
2925 2926 2927 2928
    else if (dispex_query_interface(&This->dispex, riid, ppvObject))
    {
        return *ppvObject ? S_OK : E_NOINTERFACE;
    }
2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957
    else
    {
        FIXME("interface %s not implemented\n", debugstr_guid(riid));
        return E_NOINTERFACE;
    }

    IVBSAXXMLReader_AddRef( iface );

    return S_OK;
}

static ULONG WINAPI saxxmlreader_AddRef(IVBSAXXMLReader* iface)
{
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
    TRACE("%p\n", This );
    return InterlockedIncrement( &This->ref );
}

static ULONG WINAPI saxxmlreader_Release(
    IVBSAXXMLReader* iface)
{
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
    LONG ref;

    TRACE("%p\n", This );

    ref = InterlockedDecrement( &This->ref );
    if ( ref == 0 )
    {
2958
        int i;
2959

2960 2961
        for (i = 0; i < SAXHandler_Last; i++)
        {
2962
            struct saxanyhandler_iface *saxiface = &This->saxhandlers[i].u.anyhandler;
2963

2964 2965
            if (saxiface->handler)
                IUnknown_Release(saxiface->handler);
2966

2967 2968
            if (saxiface->vbhandler)
                IUnknown_Release(saxiface->vbhandler);
2969
        }
2970

2971
        SysFreeString(This->xmldecl_version);
2972 2973
        free_bstr_pool(&This->pool);

2974
        heap_free( This );
2975 2976 2977 2978 2979 2980 2981 2982
    }

    return ref;
}
/*** IDispatch ***/
static HRESULT WINAPI saxxmlreader_GetTypeInfoCount( IVBSAXXMLReader *iface, UINT* pctinfo )
{
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
2983
    return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
2984 2985 2986 2987 2988 2989 2990
}

static HRESULT WINAPI saxxmlreader_GetTypeInfo(
    IVBSAXXMLReader *iface,
    UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
{
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
2991 2992
    return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
        iTInfo, lcid, ppTInfo);
2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003
}

static HRESULT WINAPI saxxmlreader_GetIDsOfNames(
    IVBSAXXMLReader *iface,
    REFIID riid,
    LPOLESTR* rgszNames,
    UINT cNames,
    LCID lcid,
    DISPID* rgDispId)
{
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3004 3005
    return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
        riid, rgszNames, cNames, lcid, rgDispId);
3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019
}

static HRESULT WINAPI saxxmlreader_Invoke(
    IVBSAXXMLReader *iface,
    DISPID dispIdMember,
    REFIID riid,
    LCID lcid,
    WORD wFlags,
    DISPPARAMS* pDispParams,
    VARIANT* pVarResult,
    EXCEPINFO* pExcepInfo,
    UINT* puArgErr)
{
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3020 3021
    return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
        dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
3022 3023 3024 3025 3026
}

/*** IVBSAXXMLReader methods ***/
static HRESULT WINAPI saxxmlreader_getFeature(
    IVBSAXXMLReader* iface,
3027
    BSTR feature_name,
3028
    VARIANT_BOOL *value)
3029
{
3030
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3031
    return ISAXXMLReader_getFeature(&This->ISAXXMLReader_iface, feature_name, value);
3032 3033 3034 3035
}

static HRESULT WINAPI saxxmlreader_putFeature(
    IVBSAXXMLReader* iface,
3036
    BSTR feature_name,
3037
    VARIANT_BOOL value)
3038
{
3039
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3040
    return ISAXXMLReader_putFeature(&This->ISAXXMLReader_iface, feature_name, value);
3041 3042 3043 3044
}

static HRESULT WINAPI saxxmlreader_getProperty(
    IVBSAXXMLReader* iface,
3045
    BSTR prop,
3046
    VARIANT *value)
3047
{
3048
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3049
    return internal_getProperty(This, prop, value, TRUE);
3050 3051 3052 3053
}

static HRESULT WINAPI saxxmlreader_putProperty(
    IVBSAXXMLReader* iface,
3054
    BSTR pProp,
3055 3056
    VARIANT value)
{
3057
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3058
    return internal_putProperty(This, pProp, value, TRUE);
3059 3060
}

3061
static HRESULT WINAPI saxxmlreader_get_entityResolver(
3062
    IVBSAXXMLReader* iface,
3063
    IVBSAXEntityResolver **resolver)
3064
{
3065
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3066
    return saxreader_get_handler(This, SAXEntityResolver, TRUE, (void**)resolver);
3067 3068
}

3069
static HRESULT WINAPI saxxmlreader_put_entityResolver(
3070
    IVBSAXXMLReader* iface,
3071
    IVBSAXEntityResolver *resolver)
3072
{
3073
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3074
    return saxreader_put_handler(This, SAXEntityResolver, resolver, TRUE);
3075 3076
}

3077
static HRESULT WINAPI saxxmlreader_get_contentHandler(
3078
    IVBSAXXMLReader* iface,
3079
    IVBSAXContentHandler **handler)
3080
{
3081
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3082
    return saxreader_get_handler(This, SAXContentHandler, TRUE, (void**)handler);
3083 3084
}

3085
static HRESULT WINAPI saxxmlreader_put_contentHandler(
3086
    IVBSAXXMLReader* iface,
3087
    IVBSAXContentHandler *handler)
3088
{
3089
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3090
    return saxreader_put_handler(This, SAXContentHandler, handler, TRUE);
3091 3092
}

3093
static HRESULT WINAPI saxxmlreader_get_dtdHandler(
3094
    IVBSAXXMLReader* iface,
3095
    IVBSAXDTDHandler **handler)
3096
{
3097
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3098
    return saxreader_get_handler(This, SAXDTDHandler, TRUE, (void**)handler);
3099 3100
}

3101
static HRESULT WINAPI saxxmlreader_put_dtdHandler(
3102
    IVBSAXXMLReader* iface,
3103
    IVBSAXDTDHandler *handler)
3104
{
3105
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3106
    return saxreader_put_handler(This, SAXDTDHandler, handler, TRUE);
3107 3108
}

3109
static HRESULT WINAPI saxxmlreader_get_errorHandler(
3110
    IVBSAXXMLReader* iface,
3111
    IVBSAXErrorHandler **handler)
3112
{
3113
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3114
    return saxreader_get_handler(This, SAXErrorHandler, TRUE, (void**)handler);
3115 3116
}

3117
static HRESULT WINAPI saxxmlreader_put_errorHandler(
3118
    IVBSAXXMLReader* iface,
3119
    IVBSAXErrorHandler *handler)
3120
{
3121
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3122
    return saxreader_put_handler(This, SAXErrorHandler, handler, TRUE);
3123 3124
}

3125
static HRESULT WINAPI saxxmlreader_get_baseURL(
3126
    IVBSAXXMLReader* iface,
3127
    BSTR *pBaseUrl)
3128
{
3129 3130 3131
    saxreader *This = impl_from_IVBSAXXMLReader( iface );

    FIXME("(%p)->(%p) stub\n", This, pBaseUrl);
3132 3133 3134
    return E_NOTIMPL;
}

3135
static HRESULT WINAPI saxxmlreader_put_baseURL(
3136
    IVBSAXXMLReader* iface,
3137
    BSTR pBaseUrl)
3138
{
3139
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3140
    return ISAXXMLReader_putBaseURL(&This->ISAXXMLReader_iface, pBaseUrl);
3141 3142
}

3143
static HRESULT WINAPI saxxmlreader_get_secureBaseURL(
3144
    IVBSAXXMLReader* iface,
3145
    BSTR *pSecureBaseUrl)
3146
{
3147 3148 3149
    saxreader *This = impl_from_IVBSAXXMLReader( iface );

    FIXME("(%p)->(%p) stub\n", This, pSecureBaseUrl);
3150 3151 3152
    return E_NOTIMPL;
}

3153
static HRESULT WINAPI saxxmlreader_put_secureBaseURL(
3154
    IVBSAXXMLReader* iface,
3155
    BSTR secureBaseUrl)
3156
{
3157
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3158
    return ISAXXMLReader_putSecureBaseURL(&This->ISAXXMLReader_iface, secureBaseUrl);
3159 3160 3161 3162 3163 3164
}

static HRESULT WINAPI saxxmlreader_parse(
    IVBSAXXMLReader* iface,
    VARIANT varInput)
{
3165
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3166
    return internal_parse(This, varInput, TRUE);
3167 3168 3169 3170
}

static HRESULT WINAPI saxxmlreader_parseURL(
    IVBSAXXMLReader* iface,
3171
    BSTR url)
3172
{
3173
    saxreader *This = impl_from_IVBSAXXMLReader( iface );
3174
    return internal_parseURL(This, url, TRUE);
3175 3176
}

3177
static const struct IVBSAXXMLReaderVtbl VBSAXXMLReaderVtbl =
3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189
{
    saxxmlreader_QueryInterface,
    saxxmlreader_AddRef,
    saxxmlreader_Release,
    saxxmlreader_GetTypeInfoCount,
    saxxmlreader_GetTypeInfo,
    saxxmlreader_GetIDsOfNames,
    saxxmlreader_Invoke,
    saxxmlreader_getFeature,
    saxxmlreader_putFeature,
    saxxmlreader_getProperty,
    saxxmlreader_putProperty,
3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201
    saxxmlreader_get_entityResolver,
    saxxmlreader_put_entityResolver,
    saxxmlreader_get_contentHandler,
    saxxmlreader_put_contentHandler,
    saxxmlreader_get_dtdHandler,
    saxxmlreader_put_dtdHandler,
    saxxmlreader_get_errorHandler,
    saxxmlreader_put_errorHandler,
    saxxmlreader_get_baseURL,
    saxxmlreader_put_baseURL,
    saxxmlreader_get_secureBaseURL,
    saxxmlreader_put_secureBaseURL,
3202 3203 3204 3205
    saxxmlreader_parse,
    saxxmlreader_parseURL
};

3206 3207 3208 3209 3210
/*** ISAXXMLReader interface ***/
/*** IUnknown methods ***/
static HRESULT WINAPI isaxxmlreader_QueryInterface(ISAXXMLReader* iface, REFIID riid, void **ppvObject)
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3211
    return IVBSAXXMLReader_QueryInterface(&This->IVBSAXXMLReader_iface, riid, ppvObject);
3212 3213 3214 3215 3216
}

static ULONG WINAPI isaxxmlreader_AddRef(ISAXXMLReader* iface)
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3217
    return IVBSAXXMLReader_AddRef(&This->IVBSAXXMLReader_iface);
3218 3219 3220 3221 3222
}

static ULONG WINAPI isaxxmlreader_Release(ISAXXMLReader* iface)
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3223
    return IVBSAXXMLReader_Release(&This->IVBSAXXMLReader_iface);
3224 3225 3226 3227 3228
}

/*** ISAXXMLReader methods ***/
static HRESULT WINAPI isaxxmlreader_getFeature(
        ISAXXMLReader* iface,
3229 3230
        const WCHAR *feature_name,
        VARIANT_BOOL *value)
3231 3232
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3233 3234 3235 3236 3237 3238 3239 3240 3241 3242
    saxreader_feature feature;

    TRACE("(%p)->(%s %p)\n", This, debugstr_w(feature_name), value);

    feature = get_saxreader_feature(feature_name);
    if (feature == Namespaces || feature == NamespacePrefixes)
        return get_feature_value(This, feature, value);

    FIXME("(%p)->(%s %p) stub\n", This, debugstr_w(feature_name), value);
    return E_NOTIMPL;
3243 3244 3245 3246
}

static HRESULT WINAPI isaxxmlreader_putFeature(
        ISAXXMLReader* iface,
3247 3248
        const WCHAR *feature_name,
        VARIANT_BOOL value)
3249 3250
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273
    saxreader_feature feature;

    TRACE("(%p)->(%s %x)\n", This, debugstr_w(feature_name), value);

    feature = get_saxreader_feature(feature_name);

    /* accepted cases */
    if ((feature == ExternalGeneralEntities   && value == VARIANT_FALSE) ||
        (feature == ExternalParameterEntities && value == VARIANT_FALSE) ||
         feature == Namespaces ||
         feature == NamespacePrefixes)
    {
        return set_feature_value(This, feature, value);
    }

    if (feature == LexicalHandlerParEntities || feature == ProhibitDTD)
    {
        FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature_name), value);
        return set_feature_value(This, feature, value);
    }

    FIXME("(%p)->(%s %x) stub\n", This, debugstr_w(feature_name), value);
    return E_NOTIMPL;
3274 3275 3276 3277
}

static HRESULT WINAPI isaxxmlreader_getProperty(
        ISAXXMLReader* iface,
3278 3279
        const WCHAR *prop,
        VARIANT *value)
3280 3281
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3282
    return internal_getProperty(This, prop, value, FALSE);
3283 3284 3285 3286 3287 3288 3289 3290
}

static HRESULT WINAPI isaxxmlreader_putProperty(
        ISAXXMLReader* iface,
        const WCHAR *pProp,
        VARIANT value)
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3291
    return internal_putProperty(This, pProp, value, FALSE);
3292 3293 3294 3295
}

static HRESULT WINAPI isaxxmlreader_getEntityResolver(
        ISAXXMLReader* iface,
3296
        ISAXEntityResolver **resolver)
3297 3298
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3299
    return saxreader_get_handler(This, SAXEntityResolver, FALSE, (void**)resolver);
3300 3301 3302 3303
}

static HRESULT WINAPI isaxxmlreader_putEntityResolver(
        ISAXXMLReader* iface,
3304
        ISAXEntityResolver *resolver)
3305 3306
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3307
    return saxreader_put_handler(This, SAXEntityResolver, resolver, FALSE);
3308 3309 3310 3311
}

static HRESULT WINAPI isaxxmlreader_getContentHandler(
        ISAXXMLReader* iface,
3312
        ISAXContentHandler **handler)
3313 3314
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3315
    return saxreader_get_handler(This, SAXContentHandler, FALSE, (void**)handler);
3316 3317 3318
}

static HRESULT WINAPI isaxxmlreader_putContentHandler(
3319 3320
    ISAXXMLReader* iface,
    ISAXContentHandler *handler)
3321 3322
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3323
    return saxreader_put_handler(This, SAXContentHandler, handler, FALSE);
3324 3325 3326 3327
}

static HRESULT WINAPI isaxxmlreader_getDTDHandler(
        ISAXXMLReader* iface,
3328
        ISAXDTDHandler **handler)
3329 3330
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3331
    return saxreader_get_handler(This, SAXDTDHandler, FALSE, (void**)handler);
3332 3333 3334 3335
}

static HRESULT WINAPI isaxxmlreader_putDTDHandler(
        ISAXXMLReader* iface,
3336
        ISAXDTDHandler *handler)
3337 3338
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3339
    return saxreader_put_handler(This, SAXDTDHandler, handler, FALSE);
3340 3341 3342 3343
}

static HRESULT WINAPI isaxxmlreader_getErrorHandler(
        ISAXXMLReader* iface,
3344
        ISAXErrorHandler **handler)
3345 3346
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3347
    return saxreader_get_handler(This, SAXErrorHandler, FALSE, (void**)handler);
3348 3349
}

3350
static HRESULT WINAPI isaxxmlreader_putErrorHandler(ISAXXMLReader* iface, ISAXErrorHandler *handler)
3351 3352
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3353
    return saxreader_put_handler(This, SAXErrorHandler, handler, FALSE);
3354 3355 3356 3357
}

static HRESULT WINAPI isaxxmlreader_getBaseURL(
        ISAXXMLReader* iface,
3358
        const WCHAR **base_url)
3359 3360
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3361 3362 3363

    FIXME("(%p)->(%p) stub\n", This, base_url);
    return E_NOTIMPL;
3364 3365 3366 3367 3368 3369 3370
}

static HRESULT WINAPI isaxxmlreader_putBaseURL(
        ISAXXMLReader* iface,
        const WCHAR *pBaseUrl)
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3371 3372 3373

    FIXME("(%p)->(%s) stub\n", This, debugstr_w(pBaseUrl));
    return E_NOTIMPL;
3374 3375 3376 3377 3378 3379 3380
}

static HRESULT WINAPI isaxxmlreader_getSecureBaseURL(
        ISAXXMLReader* iface,
        const WCHAR **pSecureBaseUrl)
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3381 3382
    FIXME("(%p)->(%p) stub\n", This, pSecureBaseUrl);
    return E_NOTIMPL;
3383 3384 3385 3386 3387 3388 3389
}

static HRESULT WINAPI isaxxmlreader_putSecureBaseURL(
        ISAXXMLReader* iface,
        const WCHAR *secureBaseUrl)
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3390 3391 3392

    FIXME("(%p)->(%s) stub\n", This, debugstr_w(secureBaseUrl));
    return E_NOTIMPL;
3393 3394 3395 3396 3397 3398 3399
}

static HRESULT WINAPI isaxxmlreader_parse(
        ISAXXMLReader* iface,
        VARIANT varInput)
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3400
    return internal_parse(This, varInput, FALSE);
3401 3402 3403 3404 3405 3406 3407
}

static HRESULT WINAPI isaxxmlreader_parseURL(
        ISAXXMLReader* iface,
        const WCHAR *url)
{
    saxreader *This = impl_from_ISAXXMLReader( iface );
3408
    return internal_parseURL(This, url, FALSE);
3409 3410
}

3411
static const struct ISAXXMLReaderVtbl SAXXMLReaderVtbl =
3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435
{
    isaxxmlreader_QueryInterface,
    isaxxmlreader_AddRef,
    isaxxmlreader_Release,
    isaxxmlreader_getFeature,
    isaxxmlreader_putFeature,
    isaxxmlreader_getProperty,
    isaxxmlreader_putProperty,
    isaxxmlreader_getEntityResolver,
    isaxxmlreader_putEntityResolver,
    isaxxmlreader_getContentHandler,
    isaxxmlreader_putContentHandler,
    isaxxmlreader_getDTDHandler,
    isaxxmlreader_putDTDHandler,
    isaxxmlreader_getErrorHandler,
    isaxxmlreader_putErrorHandler,
    isaxxmlreader_getBaseURL,
    isaxxmlreader_putBaseURL,
    isaxxmlreader_getSecureBaseURL,
    isaxxmlreader_putSecureBaseURL,
    isaxxmlreader_parse,
    isaxxmlreader_parseURL
};

3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446
static const tid_t saxreader_iface_tids[] = {
    IVBSAXXMLReader_tid,
    0
};
static dispex_static_data_t saxreader_dispex = {
    NULL,
    IVBSAXXMLReader_tid,
    NULL,
    saxreader_iface_tids
};

3447
HRESULT SAXXMLReader_create(MSXML_VERSION version, LPVOID *ppObj)
3448 3449 3450
{
    saxreader *reader;

3451
    TRACE("(%p)\n", ppObj);
3452

3453
    reader = heap_alloc( sizeof (*reader) );
3454 3455 3456
    if( !reader )
        return E_OUTOFMEMORY;

3457 3458
    reader->IVBSAXXMLReader_iface.lpVtbl = &VBSAXXMLReaderVtbl;
    reader->ISAXXMLReader_iface.lpVtbl = &SAXXMLReaderVtbl;
3459
    reader->ref = 1;
3460
    memset(reader->saxhandlers, 0, sizeof(reader->saxhandlers));
3461
    reader->isParsing = FALSE;
3462
    reader->xmldecl_version = NULL;
3463 3464 3465
    reader->pool.pool = NULL;
    reader->pool.index = 0;
    reader->pool.len = 0;
3466
    reader->features = Namespaces | NamespacePrefixes;
3467
    reader->version = version;
3468

3469 3470
    init_dispex(&reader->dispex, (IUnknown*)&reader->IVBSAXXMLReader_iface, &saxreader_dispex);

3471 3472
    memset(&reader->sax, 0, sizeof(xmlSAXHandler));
    reader->sax.initialized = XML_SAX2_MAGIC;
3473
    reader->sax.startDocument = libxmlStartDocument;
3474
    reader->sax.endDocument = libxmlEndDocument;
3475
    reader->sax.startElementNs = libxmlStartElementNS;
3476
    reader->sax.endElementNs = libxmlEndElementNS;
3477
    reader->sax.characters = libxmlCharacters;
3478
    reader->sax.setDocumentLocator = libxmlSetDocumentLocator;
3479
    reader->sax.comment = libxmlComment;
3480 3481
    reader->sax.error = libxmlFatalError;
    reader->sax.fatalError = libxmlFatalError;
3482
    reader->sax.cdataBlock = libxml_cdatablock;
3483
    reader->sax.resolveEntity = libxmlresolveentity;
3484

3485
    *ppObj = &reader->IVBSAXXMLReader_iface;
3486

3487
    TRACE("returning iface %p\n", *ppObj);
3488

3489 3490 3491 3492 3493
    return S_OK;
}

#else

3494
HRESULT SAXXMLReader_create(MSXML_VERSION version, LPVOID *ppObj)
3495 3496 3497 3498 3499 3500 3501
{
    MESSAGE("This program tried to use a SAX XML Reader object, but\n"
            "libxml2 support was not present at compile time.\n");
    return E_NOTIMPL;
}

#endif