[MSXML3] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / reactos / dll / win32 / msxml3 / element.c
1 /*
2 * DOM Document implementation
3 *
4 * Copyright 2005 Mike McCormack
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 #ifdef HAVE_LIBXML2
24
25 static const xmlChar DT_prefix[] = "dt";
26 static const xmlChar DT_nsURI[] = "urn:schemas-microsoft-com:datatypes";
27
28 typedef struct _domelem
29 {
30 xmlnode node;
31 IXMLDOMElement IXMLDOMElement_iface;
32 LONG ref;
33 } domelem;
34
35 static const struct nodemap_funcs domelem_attr_map;
36
37 static const tid_t domelem_se_tids[] = {
38 IXMLDOMNode_tid,
39 IXMLDOMElement_tid,
40 NULL_tid
41 };
42
43 static inline domelem *impl_from_IXMLDOMElement( IXMLDOMElement *iface )
44 {
45 return CONTAINING_RECORD(iface, domelem, IXMLDOMElement_iface);
46 }
47
48 static inline xmlNodePtr get_element( const domelem *This )
49 {
50 return This->node.node;
51 }
52
53 static HRESULT WINAPI domelem_QueryInterface(
54 IXMLDOMElement *iface,
55 REFIID riid,
56 void** ppvObject )
57 {
58 domelem *This = impl_from_IXMLDOMElement( iface );
59
60 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
61
62 if ( IsEqualGUID( riid, &IID_IXMLDOMElement ) ||
63 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
64 IsEqualGUID( riid, &IID_IDispatch ) ||
65 IsEqualGUID( riid, &IID_IUnknown ) )
66 {
67 *ppvObject = &This->IXMLDOMElement_iface;
68 }
69 else if(node_query_interface(&This->node, riid, ppvObject))
70 {
71 return *ppvObject ? S_OK : E_NOINTERFACE;
72 }
73 else if(IsEqualGUID( riid, &IID_ISupportErrorInfo ))
74 {
75 return node_create_supporterrorinfo(domelem_se_tids, ppvObject);
76 }
77 else
78 {
79 TRACE("interface %s not implemented\n", debugstr_guid(riid));
80 *ppvObject = NULL;
81 return E_NOINTERFACE;
82 }
83
84 IUnknown_AddRef( (IUnknown*)*ppvObject );
85 return S_OK;
86 }
87
88 static ULONG WINAPI domelem_AddRef(
89 IXMLDOMElement *iface )
90 {
91 domelem *This = impl_from_IXMLDOMElement( iface );
92 LONG ref = InterlockedIncrement(&This->ref);
93
94 TRACE("(%p)->(%d)\n", This, ref);
95
96 return ref;
97 }
98
99 static ULONG WINAPI domelem_Release(
100 IXMLDOMElement *iface )
101 {
102 domelem *This = impl_from_IXMLDOMElement( iface );
103 ULONG ref = InterlockedDecrement(&This->ref);
104
105 TRACE("(%p)->(%d)\n", This, ref);
106
107 if(!ref) {
108 destroy_xmlnode(&This->node);
109 heap_free(This);
110 }
111
112 return ref;
113 }
114
115 static HRESULT WINAPI domelem_GetTypeInfoCount(
116 IXMLDOMElement *iface,
117 UINT* pctinfo )
118 {
119 domelem *This = impl_from_IXMLDOMElement( iface );
120 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
121 }
122
123 static HRESULT WINAPI domelem_GetTypeInfo(
124 IXMLDOMElement *iface,
125 UINT iTInfo, LCID lcid,
126 ITypeInfo** ppTInfo )
127 {
128 domelem *This = impl_from_IXMLDOMElement( iface );
129 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface,
130 iTInfo, lcid, ppTInfo);
131 }
132
133 static HRESULT WINAPI domelem_GetIDsOfNames(
134 IXMLDOMElement *iface,
135 REFIID riid, LPOLESTR* rgszNames,
136 UINT cNames, LCID lcid, DISPID* rgDispId )
137 {
138 domelem *This = impl_from_IXMLDOMElement( iface );
139 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
140 riid, rgszNames, cNames, lcid, rgDispId);
141 }
142
143 static HRESULT WINAPI domelem_Invoke(
144 IXMLDOMElement *iface,
145 DISPID dispIdMember, REFIID riid, LCID lcid,
146 WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
147 EXCEPINFO* pExcepInfo, UINT* puArgErr )
148 {
149 domelem *This = impl_from_IXMLDOMElement( iface );
150 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
151 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
152 }
153
154 static HRESULT WINAPI domelem_get_nodeName(
155 IXMLDOMElement *iface,
156 BSTR* p )
157 {
158 domelem *This = impl_from_IXMLDOMElement( iface );
159
160 TRACE("(%p)->(%p)\n", This, p);
161
162 return node_get_nodeName(&This->node, p);
163 }
164
165 static HRESULT WINAPI domelem_get_nodeValue(
166 IXMLDOMElement *iface,
167 VARIANT* value)
168 {
169 domelem *This = impl_from_IXMLDOMElement( iface );
170
171 TRACE("(%p)->(%p)\n", This, value);
172
173 if(!value)
174 return E_INVALIDARG;
175
176 V_VT(value) = VT_NULL;
177 V_BSTR(value) = NULL; /* tests show that we should do this */
178 return S_FALSE;
179 }
180
181 static HRESULT WINAPI domelem_put_nodeValue(
182 IXMLDOMElement *iface,
183 VARIANT value)
184 {
185 domelem *This = impl_from_IXMLDOMElement( iface );
186 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
187 return E_FAIL;
188 }
189
190 static HRESULT WINAPI domelem_get_nodeType(
191 IXMLDOMElement *iface,
192 DOMNodeType* domNodeType )
193 {
194 domelem *This = impl_from_IXMLDOMElement( iface );
195
196 TRACE("(%p)->(%p)\n", This, domNodeType);
197
198 *domNodeType = NODE_ELEMENT;
199 return S_OK;
200 }
201
202 static HRESULT WINAPI domelem_get_parentNode(
203 IXMLDOMElement *iface,
204 IXMLDOMNode** parent )
205 {
206 domelem *This = impl_from_IXMLDOMElement( iface );
207
208 TRACE("(%p)->(%p)\n", This, parent);
209
210 return node_get_parent(&This->node, parent);
211 }
212
213 static HRESULT WINAPI domelem_get_childNodes(
214 IXMLDOMElement *iface,
215 IXMLDOMNodeList** outList)
216 {
217 domelem *This = impl_from_IXMLDOMElement( iface );
218
219 TRACE("(%p)->(%p)\n", This, outList);
220
221 return node_get_child_nodes(&This->node, outList);
222 }
223
224 static HRESULT WINAPI domelem_get_firstChild(
225 IXMLDOMElement *iface,
226 IXMLDOMNode** domNode)
227 {
228 domelem *This = impl_from_IXMLDOMElement( iface );
229
230 TRACE("(%p)->(%p)\n", This, domNode);
231
232 return node_get_first_child(&This->node, domNode);
233 }
234
235 static HRESULT WINAPI domelem_get_lastChild(
236 IXMLDOMElement *iface,
237 IXMLDOMNode** domNode)
238 {
239 domelem *This = impl_from_IXMLDOMElement( iface );
240
241 TRACE("(%p)->(%p)\n", This, domNode);
242
243 return node_get_last_child(&This->node, domNode);
244 }
245
246 static HRESULT WINAPI domelem_get_previousSibling(
247 IXMLDOMElement *iface,
248 IXMLDOMNode** domNode)
249 {
250 domelem *This = impl_from_IXMLDOMElement( iface );
251
252 TRACE("(%p)->(%p)\n", This, domNode);
253
254 return node_get_previous_sibling(&This->node, domNode);
255 }
256
257 static HRESULT WINAPI domelem_get_nextSibling(
258 IXMLDOMElement *iface,
259 IXMLDOMNode** domNode)
260 {
261 domelem *This = impl_from_IXMLDOMElement( iface );
262
263 TRACE("(%p)->(%p)\n", This, domNode);
264
265 return node_get_next_sibling(&This->node, domNode);
266 }
267
268 static HRESULT WINAPI domelem_get_attributes(
269 IXMLDOMElement *iface,
270 IXMLDOMNamedNodeMap** map)
271 {
272 domelem *This = impl_from_IXMLDOMElement( iface );
273
274 TRACE("(%p)->(%p)\n", This, map);
275
276 *map = create_nodemap(This->node.node, &domelem_attr_map);
277 return S_OK;
278 }
279
280 static HRESULT WINAPI domelem_insertBefore(
281 IXMLDOMElement *iface,
282 IXMLDOMNode* newNode, VARIANT refChild,
283 IXMLDOMNode** old_node)
284 {
285 domelem *This = impl_from_IXMLDOMElement( iface );
286 DOMNodeType type;
287 HRESULT hr;
288
289 TRACE("(%p)->(%p %s %p)\n", This, newNode, debugstr_variant(&refChild), old_node);
290
291 hr = IXMLDOMNode_get_nodeType(newNode, &type);
292 if (hr != S_OK) return hr;
293
294 TRACE("new node type %d\n", type);
295 switch (type)
296 {
297 case NODE_DOCUMENT:
298 case NODE_DOCUMENT_TYPE:
299 case NODE_ENTITY:
300 case NODE_NOTATION:
301 if (old_node) *old_node = NULL;
302 return E_FAIL;
303 default:
304 return node_insert_before(&This->node, newNode, &refChild, old_node);
305 }
306 }
307
308 static HRESULT WINAPI domelem_replaceChild(
309 IXMLDOMElement *iface,
310 IXMLDOMNode* newNode,
311 IXMLDOMNode* oldNode,
312 IXMLDOMNode** outOldNode)
313 {
314 domelem *This = impl_from_IXMLDOMElement( iface );
315
316 TRACE("(%p)->(%p %p %p)\n", This, newNode, oldNode, outOldNode);
317
318 return node_replace_child(&This->node, newNode, oldNode, outOldNode);
319 }
320
321 static HRESULT WINAPI domelem_removeChild(
322 IXMLDOMElement *iface,
323 IXMLDOMNode *child, IXMLDOMNode **oldChild)
324 {
325 domelem *This = impl_from_IXMLDOMElement( iface );
326 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
327 return node_remove_child(&This->node, child, oldChild);
328 }
329
330 static HRESULT WINAPI domelem_appendChild(
331 IXMLDOMElement *iface,
332 IXMLDOMNode *child, IXMLDOMNode **outChild)
333 {
334 domelem *This = impl_from_IXMLDOMElement( iface );
335 TRACE("(%p)->(%p %p)\n", This, child, outChild);
336 return node_append_child(&This->node, child, outChild);
337 }
338
339 static HRESULT WINAPI domelem_hasChildNodes(
340 IXMLDOMElement *iface,
341 VARIANT_BOOL *ret)
342 {
343 domelem *This = impl_from_IXMLDOMElement( iface );
344 TRACE("(%p)->(%p)\n", This, ret);
345 return node_has_childnodes(&This->node, ret);
346 }
347
348 static HRESULT WINAPI domelem_get_ownerDocument(
349 IXMLDOMElement *iface,
350 IXMLDOMDocument **doc)
351 {
352 domelem *This = impl_from_IXMLDOMElement( iface );
353 TRACE("(%p)->(%p)\n", This, doc);
354 return node_get_owner_doc(&This->node, doc);
355 }
356
357 static HRESULT WINAPI domelem_cloneNode(
358 IXMLDOMElement *iface,
359 VARIANT_BOOL deep, IXMLDOMNode** outNode)
360 {
361 domelem *This = impl_from_IXMLDOMElement( iface );
362 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
363 return node_clone( &This->node, deep, outNode );
364 }
365
366 static HRESULT WINAPI domelem_get_nodeTypeString(
367 IXMLDOMElement *iface,
368 BSTR* p)
369 {
370 domelem *This = impl_from_IXMLDOMElement( iface );
371 static const WCHAR elementW[] = {'e','l','e','m','e','n','t',0};
372
373 TRACE("(%p)->(%p)\n", This, p);
374
375 return return_bstr(elementW, p);
376 }
377
378 static HRESULT WINAPI domelem_get_text(
379 IXMLDOMElement *iface,
380 BSTR* p)
381 {
382 domelem *This = impl_from_IXMLDOMElement( iface );
383 TRACE("(%p)->(%p)\n", This, p);
384 return node_get_text(&This->node, p);
385 }
386
387 static HRESULT WINAPI domelem_put_text(
388 IXMLDOMElement *iface,
389 BSTR p)
390 {
391 domelem *This = impl_from_IXMLDOMElement( iface );
392 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
393 return node_put_text( &This->node, p );
394 }
395
396 static HRESULT WINAPI domelem_get_specified(
397 IXMLDOMElement *iface,
398 VARIANT_BOOL* isSpecified)
399 {
400 domelem *This = impl_from_IXMLDOMElement( iface );
401 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
402 *isSpecified = VARIANT_TRUE;
403 return S_OK;
404 }
405
406 static HRESULT WINAPI domelem_get_definition(
407 IXMLDOMElement *iface,
408 IXMLDOMNode** definitionNode)
409 {
410 domelem *This = impl_from_IXMLDOMElement( iface );
411 FIXME("(%p)->(%p)\n", This, definitionNode);
412 return E_NOTIMPL;
413 }
414
415 static inline BYTE hex_to_byte(xmlChar c)
416 {
417 if(c <= '9') return c-'0';
418 if(c <= 'F') return c-'A'+10;
419 return c-'a'+10;
420 }
421
422 static inline BYTE base64_to_byte(xmlChar c)
423 {
424 if(c == '+') return 62;
425 if(c == '/') return 63;
426 if(c <= '9') return c-'0'+52;
427 if(c <= 'Z') return c-'A';
428 return c-'a'+26;
429 }
430
431 static inline HRESULT variant_from_dt(XDR_DT dt, xmlChar* str, VARIANT* v)
432 {
433 VARIANT src;
434 HRESULT hr = S_OK;
435 BOOL handled = FALSE;
436
437 VariantInit(&src);
438
439 switch (dt)
440 {
441 case DT_INVALID:
442 case DT_STRING:
443 case DT_NMTOKEN:
444 case DT_NMTOKENS:
445 case DT_NUMBER:
446 case DT_URI:
447 case DT_UUID:
448 {
449 V_VT(v) = VT_BSTR;
450 V_BSTR(v) = bstr_from_xmlChar(str);
451
452 if(!V_BSTR(v))
453 return E_OUTOFMEMORY;
454 handled = TRUE;
455 }
456 break;
457 case DT_DATE:
458 case DT_DATE_TZ:
459 case DT_DATETIME:
460 case DT_DATETIME_TZ:
461 case DT_TIME:
462 case DT_TIME_TZ:
463 {
464 WCHAR *p, *e;
465 SYSTEMTIME st;
466 DOUBLE date = 0.0;
467
468 st.wYear = 1899;
469 st.wMonth = 12;
470 st.wDay = 30;
471 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
472
473 V_VT(&src) = VT_BSTR;
474 V_BSTR(&src) = bstr_from_xmlChar(str);
475
476 if(!V_BSTR(&src))
477 return E_OUTOFMEMORY;
478
479 p = V_BSTR(&src);
480 e = p + SysStringLen(V_BSTR(&src));
481
482 if(p+4<e && *(p+4)=='-') /* parse date (yyyy-mm-dd) */
483 {
484 st.wYear = atoiW(p);
485 st.wMonth = atoiW(p+5);
486 st.wDay = atoiW(p+8);
487 p += 10;
488
489 if(*p == 'T') p++;
490 }
491
492 if(p+2<e && *(p+2)==':') /* parse time (hh:mm:ss.?) */
493 {
494 st.wHour = atoiW(p);
495 st.wMinute = atoiW(p+3);
496 st.wSecond = atoiW(p+6);
497 p += 8;
498
499 if(*p == '.')
500 {
501 p++;
502 while(isdigitW(*p)) p++;
503 }
504 }
505
506 SystemTimeToVariantTime(&st, &date);
507 V_VT(v) = VT_DATE;
508 V_DATE(v) = date;
509
510 if(*p == '+') /* parse timezone offset (+hh:mm) */
511 V_DATE(v) += (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
512 else if(*p == '-') /* parse timezone offset (-hh:mm) */
513 V_DATE(v) -= (DOUBLE)atoiW(p+1)/24 + (DOUBLE)atoiW(p+4)/1440;
514
515 VariantClear(&src);
516 handled = TRUE;
517 }
518 break;
519 case DT_BIN_HEX:
520 {
521 SAFEARRAYBOUND sab;
522 int i, len;
523
524 len = xmlStrlen(str)/2;
525 sab.lLbound = 0;
526 sab.cElements = len;
527
528 V_VT(v) = (VT_ARRAY|VT_UI1);
529 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
530
531 if(!V_ARRAY(v))
532 return E_OUTOFMEMORY;
533
534 for(i=0; i<len; i++)
535 ((BYTE*)V_ARRAY(v)->pvData)[i] = (hex_to_byte(str[2*i])<<4)
536 + hex_to_byte(str[2*i+1]);
537 handled = TRUE;
538 }
539 break;
540 case DT_BIN_BASE64:
541 {
542 SAFEARRAYBOUND sab;
543 xmlChar *c1, *c2;
544 int i, len;
545
546 /* remove all formatting chars */
547 c1 = c2 = str;
548 len = 0;
549 while (*c2)
550 {
551 if ( *c2 == ' ' || *c2 == '\t' ||
552 *c2 == '\n' || *c2 == '\r' )
553 {
554 c2++;
555 continue;
556 }
557 *c1++ = *c2++;
558 len++;
559 }
560
561 /* skip padding */
562 if(str[len-2] == '=') i = 2;
563 else if(str[len-1] == '=') i = 1;
564 else i = 0;
565
566 sab.lLbound = 0;
567 sab.cElements = len/4*3-i;
568
569 V_VT(v) = (VT_ARRAY|VT_UI1);
570 V_ARRAY(v) = SafeArrayCreate(VT_UI1, 1, &sab);
571
572 if(!V_ARRAY(v))
573 return E_OUTOFMEMORY;
574
575 for(i=0; i<len/4; i++)
576 {
577 ((BYTE*)V_ARRAY(v)->pvData)[3*i] = (base64_to_byte(str[4*i])<<2)
578 + (base64_to_byte(str[4*i+1])>>4);
579 if(3*i+1 < sab.cElements)
580 ((BYTE*)V_ARRAY(v)->pvData)[3*i+1] = (base64_to_byte(str[4*i+1])<<4)
581 + (base64_to_byte(str[4*i+2])>>2);
582 if(3*i+2 < sab.cElements)
583 ((BYTE*)V_ARRAY(v)->pvData)[3*i+2] = (base64_to_byte(str[4*i+2])<<6)
584 + base64_to_byte(str[4*i+3]);
585 }
586 handled = TRUE;
587 }
588 break;
589 case DT_BOOLEAN:
590 V_VT(v) = VT_BOOL;
591 break;
592 case DT_FIXED_14_4:
593 V_VT(v) = VT_CY;
594 break;
595 case DT_I1:
596 V_VT(v) = VT_I1;
597 break;
598 case DT_I2:
599 V_VT(v) = VT_I2;
600 break;
601 case DT_I4:
602 case DT_INT:
603 V_VT(v) = VT_I4;
604 break;
605 case DT_I8:
606 V_VT(v) = VT_I8;
607 break;
608 case DT_R4:
609 V_VT(v) = VT_R4;
610 break;
611 case DT_FLOAT:
612 case DT_R8:
613 V_VT(v) = VT_R8;
614 break;
615 case DT_UI1:
616 V_VT(v) = VT_UI1;
617 break;
618 case DT_UI2:
619 V_VT(v) = VT_UI2;
620 break;
621 case DT_UI4:
622 V_VT(v) = VT_UI4;
623 break;
624 case DT_UI8:
625 V_VT(v) = VT_UI8;
626 break;
627 case DT_CHAR:
628 case DT_ENTITY:
629 case DT_ENTITIES:
630 case DT_ENUMERATION:
631 case DT_ID:
632 case DT_IDREF:
633 case DT_IDREFS:
634 case DT_NOTATION:
635 FIXME("need to handle dt:%s\n", debugstr_dt(dt));
636 V_VT(v) = VT_BSTR;
637 V_BSTR(v) = bstr_from_xmlChar(str);
638 if (!V_BSTR(v))
639 return E_OUTOFMEMORY;
640 handled = TRUE;
641 break;
642 default:
643 WARN("unknown type %d\n", dt);
644 }
645
646 if (!handled)
647 {
648 V_VT(&src) = VT_BSTR;
649 V_BSTR(&src) = bstr_from_xmlChar(str);
650
651 if(!V_BSTR(&src))
652 return E_OUTOFMEMORY;
653
654 hr = VariantChangeTypeEx(v, &src,
655 MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),0, V_VT(v));
656 VariantClear(&src);
657 }
658 return hr;
659 }
660
661 static XDR_DT element_get_dt(xmlNodePtr node)
662 {
663 XDR_DT dt = DT_INVALID;
664
665 TRACE("(%p)\n", node);
666 if(node->type != XML_ELEMENT_NODE)
667 {
668 FIXME("invalid element node\n");
669 return dt;
670 }
671
672 if (node->ns && xmlStrEqual(node->ns->href, DT_nsURI))
673 {
674 dt = str_to_dt(node->name, -1);
675 }
676 else
677 {
678 xmlChar* pVal = xmlGetNsProp(node, BAD_CAST "dt", DT_nsURI);
679 if (pVal)
680 {
681 dt = str_to_dt(pVal, -1);
682 xmlFree(pVal);
683 }
684 else if (node->doc)
685 {
686 IXMLDOMDocument3* doc = (IXMLDOMDocument3*)create_domdoc((xmlNodePtr)node->doc);
687 if (doc)
688 {
689 VARIANT v;
690 VariantInit(&v);
691
692 if (IXMLDOMDocument3_get_schemas(doc, &v) == S_OK &&
693 V_VT(&v) == VT_DISPATCH)
694 {
695 dt = SchemaCache_get_node_dt((IXMLDOMSchemaCollection2*)V_DISPATCH(&v), node);
696 }
697 VariantClear(&v);
698 IXMLDOMDocument3_Release(doc);
699 }
700 }
701 }
702
703 TRACE("=> dt:%s\n", debugstr_dt(dt));
704 return dt;
705 }
706
707 static HRESULT WINAPI domelem_get_nodeTypedValue(
708 IXMLDOMElement *iface,
709 VARIANT* v)
710 {
711 domelem *This = impl_from_IXMLDOMElement( iface );
712 XDR_DT dt;
713 xmlChar* content;
714 HRESULT hr;
715
716 TRACE("(%p)->(%p)\n", This, v);
717
718 if(!v) return E_INVALIDARG;
719
720 V_VT(v) = VT_NULL;
721
722 dt = element_get_dt(get_element(This));
723 content = xmlNodeGetContent(get_element(This));
724 hr = variant_from_dt(dt, content, v);
725 xmlFree(content);
726
727 return hr;
728 }
729
730 static HRESULT encode_base64(const BYTE *buf, int len, BSTR *ret)
731 {
732 static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
733 const BYTE *d = buf;
734 int bytes, pad_bytes, div;
735 DWORD needed;
736 WCHAR *ptr;
737
738 bytes = (len*8 + 5)/6;
739 pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
740
741 TRACE("%d, bytes is %d, pad bytes is %d\n", len, bytes, pad_bytes);
742 needed = bytes + pad_bytes + 1;
743
744 *ret = SysAllocStringLen(NULL, needed);
745 if (!*ret) return E_OUTOFMEMORY;
746
747 /* Three bytes of input give 4 chars of output */
748 div = len / 3;
749
750 ptr = *ret;
751 while (div > 0)
752 {
753 /* first char is the first 6 bits of the first byte*/
754 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
755 /* second char is the last 2 bits of the first byte and the first 4
756 * bits of the second byte */
757 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
758 /* third char is the last 4 bits of the second byte and the first 2
759 * bits of the third byte */
760 *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
761 /* fourth char is the remaining 6 bits of the third byte */
762 *ptr++ = b64[ d[2] & 0x3f];
763 d += 3;
764 div--;
765 }
766
767 switch (pad_bytes)
768 {
769 case 1:
770 /* first char is the first 6 bits of the first byte*/
771 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
772 /* second char is the last 2 bits of the first byte and the first 4
773 * bits of the second byte */
774 *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
775 /* third char is the last 4 bits of the second byte padded with
776 * two zeroes */
777 *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
778 /* fourth char is a = to indicate one byte of padding */
779 *ptr++ = '=';
780 break;
781 case 2:
782 /* first char is the first 6 bits of the first byte*/
783 *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
784 /* second char is the last 2 bits of the first byte padded with
785 * four zeroes*/
786 *ptr++ = b64[ ((d[0] << 4) & 0x30)];
787 /* third char is = to indicate padding */
788 *ptr++ = '=';
789 /* fourth char is = to indicate padding */
790 *ptr++ = '=';
791 break;
792 }
793
794 return S_OK;
795 }
796
797 static HRESULT encode_binhex(const BYTE *buf, int len, BSTR *ret)
798 {
799 static const char byte_to_hex[16] = "0123456789abcdef";
800 int i;
801
802 *ret = SysAllocStringLen(NULL, len*2);
803 if (!*ret) return E_OUTOFMEMORY;
804
805 for (i = 0; i < len; i++)
806 {
807 (*ret)[2*i] = byte_to_hex[buf[i] >> 4];
808 (*ret)[2*i+1] = byte_to_hex[0x0f & buf[i]];
809 }
810
811 return S_OK;
812 }
813
814 static HRESULT WINAPI domelem_put_nodeTypedValue(
815 IXMLDOMElement *iface,
816 VARIANT value)
817 {
818 domelem *This = impl_from_IXMLDOMElement( iface );
819 XDR_DT dt;
820 HRESULT hr;
821
822 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
823
824 dt = element_get_dt(get_element(This));
825 switch (dt)
826 {
827 /* for untyped node coerce to BSTR and set */
828 case DT_INVALID:
829 if (V_VT(&value) != VT_BSTR)
830 {
831 VARIANT content;
832 VariantInit(&content);
833 hr = VariantChangeType(&content, &value, 0, VT_BSTR);
834 if (hr == S_OK)
835 {
836 hr = node_set_content(&This->node, V_BSTR(&content));
837 VariantClear(&content);
838 }
839 }
840 else
841 hr = node_set_content(&This->node, V_BSTR(&value));
842 break;
843 case DT_BIN_BASE64:
844 if (V_VT(&value) == VT_BSTR)
845 hr = node_set_content(&This->node, V_BSTR(&value));
846 else if (V_VT(&value) == (VT_UI1|VT_ARRAY))
847 {
848 UINT dim = SafeArrayGetDim(V_ARRAY(&value));
849 LONG lbound, ubound;
850 BSTR encoded;
851 BYTE *ptr;
852 int len;
853
854 if (dim > 1)
855 FIXME("unexpected array dimension count %u\n", dim);
856
857 SafeArrayGetUBound(V_ARRAY(&value), 1, &ubound);
858 SafeArrayGetLBound(V_ARRAY(&value), 1, &lbound);
859
860 len = (ubound - lbound + 1)*SafeArrayGetElemsize(V_ARRAY(&value));
861
862 hr = SafeArrayAccessData(V_ARRAY(&value), (void*)&ptr);
863 if (FAILED(hr)) return hr;
864
865 hr = encode_base64(ptr, len, &encoded);
866 SafeArrayUnaccessData(V_ARRAY(&value));
867 if (FAILED(hr)) return hr;
868
869 hr = node_set_content(&This->node, encoded);
870 SysFreeString(encoded);
871 }
872 else
873 {
874 FIXME("unhandled variant type %d for dt:%s\n", V_VT(&value), debugstr_dt(dt));
875 return E_NOTIMPL;
876 }
877 break;
878 case DT_BIN_HEX:
879 if (V_VT(&value) == (VT_UI1|VT_ARRAY))
880 {
881 UINT dim = SafeArrayGetDim(V_ARRAY(&value));
882 LONG lbound, ubound;
883 BSTR encoded;
884 BYTE *ptr;
885 int len;
886
887 if (dim > 1)
888 FIXME("unexpected array dimension count %u\n", dim);
889
890 SafeArrayGetUBound(V_ARRAY(&value), 1, &ubound);
891 SafeArrayGetLBound(V_ARRAY(&value), 1, &lbound);
892
893 len = (ubound - lbound + 1)*SafeArrayGetElemsize(V_ARRAY(&value));
894
895 hr = SafeArrayAccessData(V_ARRAY(&value), (void*)&ptr);
896 if (FAILED(hr)) return hr;
897
898 hr = encode_binhex(ptr, len, &encoded);
899 SafeArrayUnaccessData(V_ARRAY(&value));
900 if (FAILED(hr)) return hr;
901
902 hr = node_set_content(&This->node, encoded);
903 SysFreeString(encoded);
904 }
905 else
906 {
907 FIXME("unhandled variant type %d for dt:%s\n", V_VT(&value), debugstr_dt(dt));
908 return E_NOTIMPL;
909 }
910 break;
911 default:
912 FIXME("not implemented for dt:%s\n", debugstr_dt(dt));
913 return E_NOTIMPL;
914 }
915
916 return hr;
917 }
918
919 static HRESULT WINAPI domelem_get_dataType(
920 IXMLDOMElement *iface,
921 VARIANT* typename)
922 {
923 domelem *This = impl_from_IXMLDOMElement( iface );
924 XDR_DT dt;
925
926 TRACE("(%p)->(%p)\n", This, typename);
927
928 if (!typename)
929 return E_INVALIDARG;
930
931 dt = element_get_dt(get_element(This));
932 switch (dt)
933 {
934 case DT_BIN_BASE64:
935 case DT_BIN_HEX:
936 case DT_BOOLEAN:
937 case DT_CHAR:
938 case DT_DATE:
939 case DT_DATE_TZ:
940 case DT_DATETIME:
941 case DT_DATETIME_TZ:
942 case DT_FIXED_14_4:
943 case DT_FLOAT:
944 case DT_I1:
945 case DT_I2:
946 case DT_I4:
947 case DT_I8:
948 case DT_INT:
949 case DT_NUMBER:
950 case DT_R4:
951 case DT_R8:
952 case DT_TIME:
953 case DT_TIME_TZ:
954 case DT_UI1:
955 case DT_UI2:
956 case DT_UI4:
957 case DT_UI8:
958 case DT_URI:
959 case DT_UUID:
960 V_VT(typename) = VT_BSTR;
961 V_BSTR(typename) = SysAllocString(dt_to_bstr(dt));
962
963 if (!V_BSTR(typename))
964 return E_OUTOFMEMORY;
965 break;
966 default:
967 /* Other types (DTD equivalents) do not return anything here,
968 * but the pointer part of the VARIANT is set to NULL */
969 V_VT(typename) = VT_NULL;
970 V_BSTR(typename) = NULL;
971 break;
972 }
973 return (V_VT(typename) != VT_NULL) ? S_OK : S_FALSE;
974 }
975
976 static HRESULT WINAPI domelem_put_dataType(
977 IXMLDOMElement *iface,
978 BSTR dtName)
979 {
980 domelem *This = impl_from_IXMLDOMElement( iface );
981 HRESULT hr = E_FAIL;
982 xmlChar *str;
983 XDR_DT dt;
984
985 TRACE("(%p)->(%s)\n", This, debugstr_w(dtName));
986
987 if(dtName == NULL)
988 return E_INVALIDARG;
989
990 dt = bstr_to_dt(dtName, -1);
991
992 /* An example of this is. The Text in the node needs to be a 0 or 1 for a boolean type.
993 This applies to changing types (string->bool) or setting a new one
994 */
995 str = xmlNodeGetContent(get_element(This));
996 hr = dt_validate(dt, str);
997 xmlFree(str);
998
999 /* Check all supported types. */
1000 if (hr == S_OK)
1001 {
1002 switch (dt)
1003 {
1004 case DT_BIN_BASE64:
1005 case DT_BIN_HEX:
1006 case DT_BOOLEAN:
1007 case DT_CHAR:
1008 case DT_DATE:
1009 case DT_DATE_TZ:
1010 case DT_DATETIME:
1011 case DT_DATETIME_TZ:
1012 case DT_FIXED_14_4:
1013 case DT_FLOAT:
1014 case DT_I1:
1015 case DT_I2:
1016 case DT_I4:
1017 case DT_I8:
1018 case DT_INT:
1019 case DT_NMTOKEN:
1020 case DT_NMTOKENS:
1021 case DT_NUMBER:
1022 case DT_R4:
1023 case DT_R8:
1024 case DT_STRING:
1025 case DT_TIME:
1026 case DT_TIME_TZ:
1027 case DT_UI1:
1028 case DT_UI2:
1029 case DT_UI4:
1030 case DT_UI8:
1031 case DT_URI:
1032 case DT_UUID:
1033 {
1034 xmlAttrPtr attr = xmlHasNsProp(get_element(This), DT_prefix, DT_nsURI);
1035 if (attr)
1036 {
1037 attr = xmlSetNsProp(get_element(This), attr->ns, DT_prefix, dt_to_str(dt));
1038 hr = S_OK;
1039 }
1040 else
1041 {
1042 xmlNsPtr ns = xmlNewNs(get_element(This), DT_nsURI, DT_prefix);
1043 if (ns)
1044 {
1045 attr = xmlNewNsProp(get_element(This), ns, DT_prefix, dt_to_str(dt));
1046 if (attr)
1047 {
1048 xmlAddChild(get_element(This), (xmlNodePtr)attr);
1049 hr = S_OK;
1050 }
1051 else
1052 ERR("Failed to create Attribute\n");
1053 }
1054 else
1055 ERR("Failed to create Namespace\n");
1056 }
1057 }
1058 break;
1059 default:
1060 FIXME("need to handle dt:%s\n", debugstr_dt(dt));
1061 break;
1062 }
1063 }
1064
1065 return hr;
1066 }
1067
1068 static HRESULT WINAPI domelem_get_xml(
1069 IXMLDOMElement *iface,
1070 BSTR* p)
1071 {
1072 domelem *This = impl_from_IXMLDOMElement( iface );
1073
1074 TRACE("(%p)->(%p)\n", This, p);
1075
1076 return node_get_xml(&This->node, TRUE, p);
1077 }
1078
1079 static HRESULT WINAPI domelem_transformNode(
1080 IXMLDOMElement *iface,
1081 IXMLDOMNode *node, BSTR *p)
1082 {
1083 domelem *This = impl_from_IXMLDOMElement( iface );
1084 TRACE("(%p)->(%p %p)\n", This, node, p);
1085 return node_transform_node(&This->node, node, p);
1086 }
1087
1088 static HRESULT WINAPI domelem_selectNodes(
1089 IXMLDOMElement *iface,
1090 BSTR p, IXMLDOMNodeList** outList)
1091 {
1092 domelem *This = impl_from_IXMLDOMElement( iface );
1093 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1094 return node_select_nodes(&This->node, p, outList);
1095 }
1096
1097 static HRESULT WINAPI domelem_selectSingleNode(
1098 IXMLDOMElement *iface,
1099 BSTR p, IXMLDOMNode** outNode)
1100 {
1101 domelem *This = impl_from_IXMLDOMElement( iface );
1102 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1103 return node_select_singlenode(&This->node, p, outNode);
1104 }
1105
1106 static HRESULT WINAPI domelem_get_parsed(
1107 IXMLDOMElement *iface,
1108 VARIANT_BOOL* isParsed)
1109 {
1110 domelem *This = impl_from_IXMLDOMElement( iface );
1111 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1112 *isParsed = VARIANT_TRUE;
1113 return S_OK;
1114 }
1115
1116 static HRESULT WINAPI domelem_get_namespaceURI(
1117 IXMLDOMElement *iface,
1118 BSTR* p)
1119 {
1120 domelem *This = impl_from_IXMLDOMElement( iface );
1121 TRACE("(%p)->(%p)\n", This, p);
1122 return node_get_namespaceURI(&This->node, p);
1123 }
1124
1125 static HRESULT WINAPI domelem_get_prefix(
1126 IXMLDOMElement *iface,
1127 BSTR* prefix)
1128 {
1129 domelem *This = impl_from_IXMLDOMElement( iface );
1130 TRACE("(%p)->(%p)\n", This, prefix);
1131 return node_get_prefix( &This->node, prefix );
1132 }
1133
1134 static HRESULT WINAPI domelem_get_baseName(
1135 IXMLDOMElement *iface,
1136 BSTR* name)
1137 {
1138 domelem *This = impl_from_IXMLDOMElement( iface );
1139 TRACE("(%p)->(%p)\n", This, name);
1140 return node_get_base_name( &This->node, name );
1141 }
1142
1143 static HRESULT WINAPI domelem_transformNodeToObject(
1144 IXMLDOMElement *iface,
1145 IXMLDOMNode* domNode, VARIANT var1)
1146 {
1147 domelem *This = impl_from_IXMLDOMElement( iface );
1148 FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
1149 return E_NOTIMPL;
1150 }
1151
1152 static HRESULT WINAPI domelem_get_tagName(
1153 IXMLDOMElement *iface,
1154 BSTR* p)
1155 {
1156 domelem *This = impl_from_IXMLDOMElement( iface );
1157 xmlNodePtr element;
1158 const xmlChar *prefix;
1159 xmlChar *qname;
1160
1161 TRACE("(%p)->(%p)\n", This, p );
1162
1163 if (!p) return E_INVALIDARG;
1164
1165 element = get_element( This );
1166 if ( !element )
1167 return E_FAIL;
1168
1169 prefix = element->ns ? element->ns->prefix : NULL;
1170 qname = xmlBuildQName(element->name, prefix, NULL, 0);
1171
1172 *p = bstr_from_xmlChar(qname);
1173 if (qname != element->name) xmlFree(qname);
1174
1175 return *p ? S_OK : E_OUTOFMEMORY;
1176 }
1177
1178 static HRESULT WINAPI domelem_getAttribute(
1179 IXMLDOMElement *iface,
1180 BSTR name, VARIANT* value)
1181 {
1182 domelem *This = impl_from_IXMLDOMElement( iface );
1183 xmlNodePtr element;
1184 xmlChar *xml_name, *xml_value = NULL;
1185 xmlChar *local, *prefix;
1186 HRESULT hr = S_FALSE;
1187 xmlNsPtr ns;
1188
1189 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
1190
1191 if(!value || !name)
1192 return E_INVALIDARG;
1193
1194 element = get_element( This );
1195 if ( !element )
1196 return E_FAIL;
1197
1198 V_BSTR(value) = NULL;
1199 V_VT(value) = VT_NULL;
1200
1201 xml_name = xmlchar_from_wchar( name );
1202
1203 if(!xmlValidateNameValue(xml_name))
1204 hr = E_FAIL;
1205 else
1206 {
1207 if ((local = xmlSplitQName2(xml_name, &prefix)))
1208 {
1209 if (xmlStrEqual(prefix, BAD_CAST "xmlns"))
1210 {
1211 ns = xmlSearchNs(element->doc, element, local);
1212 if (ns)
1213 xml_value = xmlStrdup(ns->href);
1214 }
1215 else
1216 {
1217 ns = xmlSearchNs(element->doc, element, prefix);
1218 if (ns)
1219 xml_value = xmlGetNsProp(element, local, ns->href);
1220 }
1221
1222 xmlFree(prefix);
1223 xmlFree(local);
1224 }
1225 else
1226 xml_value = xmlGetNsProp(element, xml_name, NULL);
1227 }
1228
1229 heap_free(xml_name);
1230 if(xml_value)
1231 {
1232 V_VT(value) = VT_BSTR;
1233 V_BSTR(value) = bstr_from_xmlChar( xml_value );
1234 xmlFree(xml_value);
1235 hr = S_OK;
1236 }
1237
1238 return hr;
1239 }
1240
1241 static HRESULT WINAPI domelem_setAttribute(
1242 IXMLDOMElement *iface,
1243 BSTR name, VARIANT value)
1244 {
1245 domelem *This = impl_from_IXMLDOMElement( iface );
1246 xmlChar *xml_name, *xml_value, *local, *prefix;
1247 xmlNodePtr element;
1248 HRESULT hr = S_OK;
1249
1250 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_variant(&value));
1251
1252 element = get_element( This );
1253 if ( !element )
1254 return E_FAIL;
1255
1256 if (V_VT(&value) != VT_BSTR)
1257 {
1258 VARIANT var;
1259
1260 VariantInit(&var);
1261 hr = VariantChangeType(&var, &value, 0, VT_BSTR);
1262 if (hr != S_OK)
1263 {
1264 FIXME("VariantChangeType failed\n");
1265 return hr;
1266 }
1267
1268 xml_value = xmlchar_from_wchar(V_BSTR(&var));
1269 VariantClear(&var);
1270 }
1271 else
1272 xml_value = xmlchar_from_wchar(V_BSTR(&value));
1273
1274 xml_name = xmlchar_from_wchar( name );
1275
1276 if ((local = xmlSplitQName2(xml_name, &prefix)))
1277 {
1278 static const xmlChar* xmlnsA = (const xmlChar*)"xmlns";
1279 xmlNsPtr ns = NULL;
1280
1281 /* it's not allowed to modify existing namespace definition */
1282 if (xmlStrEqual(prefix, xmlnsA))
1283 ns = xmlSearchNs(element->doc, element, local);
1284
1285 xmlFree(prefix);
1286 xmlFree(local);
1287
1288 if (ns)
1289 {
1290 int cmp = xmlStrEqual(ns->href, xml_value);
1291 heap_free(xml_value);
1292 heap_free(xml_name);
1293 return cmp ? S_OK : E_INVALIDARG;
1294 }
1295 }
1296
1297 if (!xmlSetNsProp(element, NULL, xml_name, xml_value))
1298 hr = E_FAIL;
1299
1300 heap_free(xml_value);
1301 heap_free(xml_name);
1302
1303 return hr;
1304 }
1305
1306 static HRESULT WINAPI domelem_removeAttribute(
1307 IXMLDOMElement *iface,
1308 BSTR p)
1309 {
1310 domelem *This = impl_from_IXMLDOMElement( iface );
1311 IXMLDOMNamedNodeMap *attr;
1312 HRESULT hr;
1313
1314 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
1315
1316 hr = IXMLDOMElement_get_attributes(iface, &attr);
1317 if (hr != S_OK) return hr;
1318
1319 hr = IXMLDOMNamedNodeMap_removeNamedItem(attr, p, NULL);
1320 IXMLDOMNamedNodeMap_Release(attr);
1321
1322 return hr;
1323 }
1324
1325 static HRESULT WINAPI domelem_getAttributeNode(
1326 IXMLDOMElement *iface,
1327 BSTR p, IXMLDOMAttribute** attributeNode )
1328 {
1329 domelem *This = impl_from_IXMLDOMElement( iface );
1330 xmlChar *local, *prefix, *nameA;
1331 HRESULT hr = S_FALSE;
1332 xmlNodePtr element;
1333 xmlAttrPtr attr;
1334
1335 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), attributeNode);
1336
1337 element = get_element( This );
1338 if (!element) return E_FAIL;
1339
1340 if (attributeNode) *attributeNode = NULL;
1341
1342 nameA = xmlchar_from_wchar(p);
1343 if (!xmlValidateNameValue(nameA))
1344 {
1345 heap_free(nameA);
1346 return E_FAIL;
1347 }
1348
1349 if (!attributeNode)
1350 {
1351 heap_free(nameA);
1352 return S_FALSE;
1353 }
1354
1355 *attributeNode = NULL;
1356
1357 local = xmlSplitQName2(nameA, &prefix);
1358
1359 if (local)
1360 {
1361 /* try to get namespace for supplied qualified name */
1362 xmlNsPtr ns = xmlSearchNs(element->doc, element, prefix);
1363 xmlFree(prefix);
1364
1365 attr = xmlHasNsProp(element, local, ns ? ns->href : NULL);
1366 xmlFree(local);
1367 }
1368 else
1369 {
1370 attr = xmlHasProp(element, nameA);
1371 /* attribute has attached namespace and we requested non-qualified
1372 name - it's a failure case */
1373 if (attr && attr->ns) attr = NULL;
1374 }
1375
1376 heap_free(nameA);
1377
1378 if (attr)
1379 {
1380 IUnknown *unk = create_attribute((xmlNodePtr)attr);
1381 hr = IUnknown_QueryInterface(unk, &IID_IXMLDOMAttribute, (void**)attributeNode);
1382 IUnknown_Release(unk);
1383 }
1384
1385 return hr;
1386 }
1387
1388 static HRESULT WINAPI domelem_setAttributeNode(
1389 IXMLDOMElement *iface,
1390 IXMLDOMAttribute* attribute,
1391 IXMLDOMAttribute** old)
1392 {
1393 domelem *This = impl_from_IXMLDOMElement( iface );
1394 static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
1395 xmlChar *name, *value;
1396 BSTR nameW, prefix;
1397 xmlnode *attr_node;
1398 xmlAttrPtr attr;
1399 VARIANT valueW;
1400 HRESULT hr;
1401
1402 FIXME("(%p)->(%p %p): semi-stub\n", This, attribute, old);
1403
1404 if (!attribute) return E_INVALIDARG;
1405
1406 attr_node = get_node_obj((IXMLDOMNode*)attribute);
1407 if (!attr_node) return E_FAIL;
1408
1409 if (attr_node->parent)
1410 {
1411 WARN("attempt to add already used attribute\n");
1412 return E_FAIL;
1413 }
1414
1415 hr = IXMLDOMAttribute_get_nodeName(attribute, &nameW);
1416 if (hr != S_OK) return hr;
1417
1418 /* adding xmlns attribute doesn't change a tree or existing namespace definition */
1419 if (!strcmpW(nameW, xmlnsW))
1420 {
1421 SysFreeString(nameW);
1422 return DISP_E_UNKNOWNNAME;
1423 }
1424
1425 hr = IXMLDOMAttribute_get_nodeValue(attribute, &valueW);
1426 if (hr != S_OK)
1427 {
1428 SysFreeString(nameW);
1429 return hr;
1430 }
1431
1432 if (old) *old = NULL;
1433
1434 TRACE("attribute: %s=%s\n", debugstr_w(nameW), debugstr_w(V_BSTR(&valueW)));
1435
1436 hr = IXMLDOMAttribute_get_prefix(attribute, &prefix);
1437 if (hr == S_OK)
1438 {
1439 FIXME("namespaces not supported: %s\n", debugstr_w(prefix));
1440 SysFreeString(prefix);
1441 }
1442
1443 name = xmlchar_from_wchar(nameW);
1444 value = xmlchar_from_wchar(V_BSTR(&valueW));
1445
1446 if (!name || !value)
1447 {
1448 SysFreeString(nameW);
1449 VariantClear(&valueW);
1450 heap_free(name);
1451 heap_free(value);
1452 return E_OUTOFMEMORY;
1453 }
1454
1455 attr = xmlSetNsProp(get_element(This), NULL, name, value);
1456 if (attr)
1457 attr_node->parent = (IXMLDOMNode*)iface;
1458
1459 SysFreeString(nameW);
1460 VariantClear(&valueW);
1461 heap_free(name);
1462 heap_free(value);
1463
1464 return attr ? S_OK : E_FAIL;
1465 }
1466
1467 static HRESULT WINAPI domelem_removeAttributeNode(
1468 IXMLDOMElement *iface,
1469 IXMLDOMAttribute* domAttribute,
1470 IXMLDOMAttribute** attributeNode)
1471 {
1472 domelem *This = impl_from_IXMLDOMElement( iface );
1473 FIXME("(%p)->(%p %p)\n", This, domAttribute, attributeNode);
1474 return E_NOTIMPL;
1475 }
1476
1477 static HRESULT WINAPI domelem_getElementsByTagName(
1478 IXMLDOMElement *iface,
1479 BSTR tagName, IXMLDOMNodeList** resultList)
1480 {
1481 domelem *This = impl_from_IXMLDOMElement( iface );
1482 xmlChar *query;
1483 HRESULT hr;
1484 BOOL XPath;
1485
1486 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1487
1488 if (!tagName || !resultList) return E_INVALIDARG;
1489
1490 XPath = is_xpathmode(get_element(This)->doc);
1491 set_xpathmode(get_element(This)->doc, TRUE);
1492 query = tagName_to_XPath(tagName);
1493 hr = create_selection(get_element(This), query, resultList);
1494 xmlFree(query);
1495 set_xpathmode(get_element(This)->doc, XPath);
1496
1497 return hr;
1498 }
1499
1500 static HRESULT WINAPI domelem_normalize(
1501 IXMLDOMElement *iface )
1502 {
1503 domelem *This = impl_from_IXMLDOMElement( iface );
1504 FIXME("%p\n", This);
1505 return E_NOTIMPL;
1506 }
1507
1508 static const struct IXMLDOMElementVtbl domelem_vtbl =
1509 {
1510 domelem_QueryInterface,
1511 domelem_AddRef,
1512 domelem_Release,
1513 domelem_GetTypeInfoCount,
1514 domelem_GetTypeInfo,
1515 domelem_GetIDsOfNames,
1516 domelem_Invoke,
1517 domelem_get_nodeName,
1518 domelem_get_nodeValue,
1519 domelem_put_nodeValue,
1520 domelem_get_nodeType,
1521 domelem_get_parentNode,
1522 domelem_get_childNodes,
1523 domelem_get_firstChild,
1524 domelem_get_lastChild,
1525 domelem_get_previousSibling,
1526 domelem_get_nextSibling,
1527 domelem_get_attributes,
1528 domelem_insertBefore,
1529 domelem_replaceChild,
1530 domelem_removeChild,
1531 domelem_appendChild,
1532 domelem_hasChildNodes,
1533 domelem_get_ownerDocument,
1534 domelem_cloneNode,
1535 domelem_get_nodeTypeString,
1536 domelem_get_text,
1537 domelem_put_text,
1538 domelem_get_specified,
1539 domelem_get_definition,
1540 domelem_get_nodeTypedValue,
1541 domelem_put_nodeTypedValue,
1542 domelem_get_dataType,
1543 domelem_put_dataType,
1544 domelem_get_xml,
1545 domelem_transformNode,
1546 domelem_selectNodes,
1547 domelem_selectSingleNode,
1548 domelem_get_parsed,
1549 domelem_get_namespaceURI,
1550 domelem_get_prefix,
1551 domelem_get_baseName,
1552 domelem_transformNodeToObject,
1553 domelem_get_tagName,
1554 domelem_getAttribute,
1555 domelem_setAttribute,
1556 domelem_removeAttribute,
1557 domelem_getAttributeNode,
1558 domelem_setAttributeNode,
1559 domelem_removeAttributeNode,
1560 domelem_getElementsByTagName,
1561 domelem_normalize,
1562 };
1563
1564 static HRESULT domelem_get_qualified_item(const xmlNodePtr node, BSTR name, BSTR uri,
1565 IXMLDOMNode **item)
1566 {
1567 xmlAttrPtr attr;
1568 xmlChar *nameA;
1569 xmlChar *href;
1570
1571 TRACE("(%p)->(%s %s %p)\n", node, debugstr_w(name), debugstr_w(uri), item);
1572
1573 if (!name || !item) return E_INVALIDARG;
1574
1575 if (uri && *uri)
1576 {
1577 href = xmlchar_from_wchar(uri);
1578 if (!href) return E_OUTOFMEMORY;
1579 }
1580 else
1581 href = NULL;
1582
1583 nameA = xmlchar_from_wchar(name);
1584 if (!nameA)
1585 {
1586 heap_free(href);
1587 return E_OUTOFMEMORY;
1588 }
1589
1590 attr = xmlHasNsProp(node, nameA, href);
1591
1592 heap_free(nameA);
1593 heap_free(href);
1594
1595 if (!attr)
1596 {
1597 *item = NULL;
1598 return S_FALSE;
1599 }
1600
1601 *item = create_node((xmlNodePtr)attr);
1602
1603 return S_OK;
1604 }
1605
1606 static HRESULT domelem_get_named_item(const xmlNodePtr node, BSTR name, IXMLDOMNode **item)
1607 {
1608 xmlChar *nameA, *local, *prefix;
1609 BSTR uriW, localW;
1610 xmlNsPtr ns;
1611 HRESULT hr;
1612
1613 TRACE("(%p)->(%s %p)\n", node, debugstr_w(name), item );
1614
1615 nameA = xmlchar_from_wchar(name);
1616 local = xmlSplitQName2(nameA, &prefix);
1617 heap_free(nameA);
1618
1619 if (!local)
1620 return domelem_get_qualified_item(node, name, NULL, item);
1621
1622 /* try to get namespace uri for supplied qualified name */
1623 ns = xmlSearchNs(node->doc, node, prefix);
1624
1625 xmlFree(prefix);
1626
1627 if (!ns)
1628 {
1629 xmlFree(local);
1630 if (item) *item = NULL;
1631 return item ? S_FALSE : E_INVALIDARG;
1632 }
1633
1634 uriW = bstr_from_xmlChar(ns->href);
1635 localW = bstr_from_xmlChar(local);
1636 xmlFree(local);
1637
1638 TRACE("got qualified node %s, uri=%s\n", debugstr_w(localW), debugstr_w(uriW));
1639
1640 hr = domelem_get_qualified_item(node, localW, uriW, item);
1641
1642 SysFreeString(localW);
1643 SysFreeString(uriW);
1644
1645 return hr;
1646 }
1647
1648 static HRESULT domelem_set_named_item(xmlNodePtr node, IXMLDOMNode *newItem, IXMLDOMNode **namedItem)
1649 {
1650 xmlNodePtr nodeNew;
1651 xmlnode *ThisNew;
1652
1653 TRACE("(%p)->(%p %p)\n", node, newItem, namedItem );
1654
1655 if(!newItem)
1656 return E_INVALIDARG;
1657
1658 if(namedItem) *namedItem = NULL;
1659
1660 /* Must be an Attribute */
1661 ThisNew = get_node_obj( newItem );
1662 if(!ThisNew) return E_FAIL;
1663
1664 if(ThisNew->node->type != XML_ATTRIBUTE_NODE)
1665 return E_FAIL;
1666
1667 if(!ThisNew->node->parent)
1668 if(xmldoc_remove_orphan(ThisNew->node->doc, ThisNew->node) != S_OK)
1669 WARN("%p is not an orphan of %p\n", ThisNew->node, ThisNew->node->doc);
1670
1671 nodeNew = xmlAddChild(node, ThisNew->node);
1672
1673 if(namedItem)
1674 *namedItem = create_node( nodeNew );
1675 return S_OK;
1676 }
1677
1678 static HRESULT domelem_remove_qualified_item(xmlNodePtr node, BSTR name, BSTR uri, IXMLDOMNode **item)
1679 {
1680 xmlChar *nameA, *href;
1681 xmlAttrPtr attr;
1682
1683 TRACE("(%p)->(%s %s %p)\n", node, debugstr_w(name), debugstr_w(uri), item);
1684
1685 if (!name) return E_INVALIDARG;
1686
1687 if (uri && *uri)
1688 {
1689 href = xmlchar_from_wchar(uri);
1690 if (!href) return E_OUTOFMEMORY;
1691 }
1692 else
1693 href = NULL;
1694
1695 nameA = xmlchar_from_wchar(name);
1696 if (!nameA)
1697 {
1698 heap_free(href);
1699 return E_OUTOFMEMORY;
1700 }
1701
1702 attr = xmlHasNsProp(node, nameA, href);
1703
1704 heap_free(nameA);
1705 heap_free(href);
1706
1707 if (!attr)
1708 {
1709 if (item) *item = NULL;
1710 return S_FALSE;
1711 }
1712
1713 if (item)
1714 {
1715 xmlUnlinkNode( (xmlNodePtr) attr );
1716 xmldoc_add_orphan( attr->doc, (xmlNodePtr) attr );
1717 *item = create_node( (xmlNodePtr) attr );
1718 }
1719 else
1720 {
1721 if (xmlRemoveProp(attr) == -1)
1722 ERR("xmlRemoveProp failed\n");
1723 }
1724
1725 return S_OK;
1726 }
1727
1728 static HRESULT domelem_remove_named_item(xmlNodePtr node, BSTR name, IXMLDOMNode **item)
1729 {
1730 TRACE("(%p)->(%s %p)\n", node, debugstr_w(name), item);
1731 return domelem_remove_qualified_item(node, name, NULL, item);
1732 }
1733
1734 static HRESULT domelem_get_item(const xmlNodePtr node, LONG index, IXMLDOMNode **item)
1735 {
1736 xmlAttrPtr curr;
1737 LONG attrIndex;
1738
1739 TRACE("(%p)->(%d %p)\n", node, index, item);
1740
1741 *item = NULL;
1742
1743 if (index < 0)
1744 return S_FALSE;
1745
1746 curr = node->properties;
1747
1748 for (attrIndex = 0; attrIndex < index; attrIndex++) {
1749 if (curr->next == NULL)
1750 return S_FALSE;
1751 else
1752 curr = curr->next;
1753 }
1754
1755 *item = create_node( (xmlNodePtr) curr );
1756
1757 return S_OK;
1758 }
1759
1760 static HRESULT domelem_get_length(const xmlNodePtr node, LONG *length)
1761 {
1762 xmlAttrPtr first;
1763 xmlAttrPtr curr;
1764 LONG attrCount;
1765
1766 TRACE("(%p)->(%p)\n", node, length);
1767
1768 if( !length )
1769 return E_INVALIDARG;
1770
1771 first = node->properties;
1772 if (first == NULL) {
1773 *length = 0;
1774 return S_OK;
1775 }
1776
1777 curr = first;
1778 attrCount = 1;
1779 while (curr->next) {
1780 attrCount++;
1781 curr = curr->next;
1782 }
1783 *length = attrCount;
1784
1785 return S_OK;
1786 }
1787
1788 static HRESULT domelem_next_node(const xmlNodePtr node, LONG *iter, IXMLDOMNode **nextNode)
1789 {
1790 xmlAttrPtr curr;
1791 LONG i;
1792
1793 TRACE("(%p)->(%d: %p)\n", node, *iter, nextNode);
1794
1795 *nextNode = NULL;
1796
1797 curr = node->properties;
1798
1799 for (i = 0; i < *iter; i++) {
1800 if (curr->next == NULL)
1801 return S_FALSE;
1802 else
1803 curr = curr->next;
1804 }
1805
1806 (*iter)++;
1807 *nextNode = create_node((xmlNodePtr)curr);
1808
1809 return S_OK;
1810 }
1811
1812 static const struct nodemap_funcs domelem_attr_map = {
1813 domelem_get_named_item,
1814 domelem_set_named_item,
1815 domelem_remove_named_item,
1816 domelem_get_item,
1817 domelem_get_length,
1818 domelem_get_qualified_item,
1819 domelem_remove_qualified_item,
1820 domelem_next_node
1821 };
1822
1823 static const tid_t domelem_iface_tids[] = {
1824 IXMLDOMElement_tid,
1825 0
1826 };
1827
1828 static dispex_static_data_t domelem_dispex = {
1829 NULL,
1830 IXMLDOMElement_tid,
1831 NULL,
1832 domelem_iface_tids
1833 };
1834
1835 IUnknown* create_element( xmlNodePtr element )
1836 {
1837 domelem *This;
1838
1839 This = heap_alloc( sizeof *This );
1840 if ( !This )
1841 return NULL;
1842
1843 This->IXMLDOMElement_iface.lpVtbl = &domelem_vtbl;
1844 This->ref = 1;
1845
1846 init_xmlnode(&This->node, element, (IXMLDOMNode*)&This->IXMLDOMElement_iface, &domelem_dispex);
1847
1848 return (IUnknown*)&This->IXMLDOMElement_iface;
1849 }
1850
1851 #endif