120530c800ccfaa41f2a7c46f6207660bcd4e65c
[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 HRESULT hr = S_FALSE;
1186
1187 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), value);
1188
1189 if(!value || !name)
1190 return E_INVALIDARG;
1191
1192 element = get_element( This );
1193 if ( !element )
1194 return E_FAIL;
1195
1196 V_BSTR(value) = NULL;
1197 V_VT(value) = VT_NULL;
1198
1199 xml_name = xmlchar_from_wchar( name );
1200
1201 if(!xmlValidateNameValue(xml_name))
1202 hr = E_FAIL;
1203 else
1204 xml_value = xmlGetNsProp(element, xml_name, NULL);
1205
1206 heap_free(xml_name);
1207 if(xml_value)
1208 {
1209 V_VT(value) = VT_BSTR;
1210 V_BSTR(value) = bstr_from_xmlChar( xml_value );
1211 xmlFree(xml_value);
1212 hr = S_OK;
1213 }
1214
1215 return hr;
1216 }
1217
1218 static HRESULT WINAPI domelem_setAttribute(
1219 IXMLDOMElement *iface,
1220 BSTR name, VARIANT value)
1221 {
1222 domelem *This = impl_from_IXMLDOMElement( iface );
1223 xmlChar *xml_name, *xml_value, *local, *prefix;
1224 xmlNodePtr element;
1225 HRESULT hr = S_OK;
1226
1227 TRACE("(%p)->(%s %s)\n", This, debugstr_w(name), debugstr_variant(&value));
1228
1229 element = get_element( This );
1230 if ( !element )
1231 return E_FAIL;
1232
1233 if (V_VT(&value) != VT_BSTR)
1234 {
1235 VARIANT var;
1236
1237 VariantInit(&var);
1238 hr = VariantChangeType(&var, &value, 0, VT_BSTR);
1239 if (hr != S_OK)
1240 {
1241 FIXME("VariantChangeType failed\n");
1242 return hr;
1243 }
1244
1245 xml_value = xmlchar_from_wchar(V_BSTR(&var));
1246 VariantClear(&var);
1247 }
1248 else
1249 xml_value = xmlchar_from_wchar(V_BSTR(&value));
1250
1251 xml_name = xmlchar_from_wchar( name );
1252
1253 if ((local = xmlSplitQName2(xml_name, &prefix)))
1254 {
1255 static const xmlChar* xmlnsA = (const xmlChar*)"xmlns";
1256 xmlNsPtr ns = NULL;
1257
1258 /* it's not allowed to modify existing namespace definition */
1259 if (xmlStrEqual(prefix, xmlnsA))
1260 ns = xmlSearchNs(element->doc, element, local);
1261
1262 xmlFree(prefix);
1263 xmlFree(local);
1264
1265 if (ns)
1266 return xmlStrEqual(ns->href, xml_value) ? S_OK : E_INVALIDARG;
1267 }
1268
1269 if (!xmlSetNsProp(element, NULL, xml_name, xml_value))
1270 hr = E_FAIL;
1271
1272 heap_free(xml_value);
1273 heap_free(xml_name);
1274
1275 return hr;
1276 }
1277
1278 static HRESULT WINAPI domelem_removeAttribute(
1279 IXMLDOMElement *iface,
1280 BSTR p)
1281 {
1282 domelem *This = impl_from_IXMLDOMElement( iface );
1283 IXMLDOMNamedNodeMap *attr;
1284 HRESULT hr;
1285
1286 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
1287
1288 hr = IXMLDOMElement_get_attributes(iface, &attr);
1289 if (hr != S_OK) return hr;
1290
1291 hr = IXMLDOMNamedNodeMap_removeNamedItem(attr, p, NULL);
1292 IXMLDOMNamedNodeMap_Release(attr);
1293
1294 return hr;
1295 }
1296
1297 static HRESULT WINAPI domelem_getAttributeNode(
1298 IXMLDOMElement *iface,
1299 BSTR p, IXMLDOMAttribute** attributeNode )
1300 {
1301 domelem *This = impl_from_IXMLDOMElement( iface );
1302 xmlChar *local, *prefix, *nameA;
1303 HRESULT hr = S_FALSE;
1304 xmlNodePtr element;
1305 xmlAttrPtr attr;
1306
1307 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), attributeNode);
1308
1309 element = get_element( This );
1310 if (!element) return E_FAIL;
1311
1312 if (attributeNode) *attributeNode = NULL;
1313
1314 nameA = xmlchar_from_wchar(p);
1315 if (!xmlValidateNameValue(nameA))
1316 {
1317 heap_free(nameA);
1318 return E_FAIL;
1319 }
1320
1321 if (!attributeNode)
1322 {
1323 heap_free(nameA);
1324 return S_FALSE;
1325 }
1326
1327 *attributeNode = NULL;
1328
1329 local = xmlSplitQName2(nameA, &prefix);
1330
1331 if (local)
1332 {
1333 /* try to get namespace for supplied qualified name */
1334 xmlNsPtr ns = xmlSearchNs(element->doc, element, prefix);
1335 xmlFree(prefix);
1336
1337 attr = xmlHasNsProp(element, local, ns ? ns->href : NULL);
1338 xmlFree(local);
1339 }
1340 else
1341 {
1342 attr = xmlHasProp(element, nameA);
1343 /* attribute has attached namespace and we requested non-qualified
1344 name - it's a failure case */
1345 if (attr && attr->ns) attr = NULL;
1346 }
1347
1348 heap_free(nameA);
1349
1350 if (attr)
1351 {
1352 IUnknown *unk = create_attribute((xmlNodePtr)attr);
1353 hr = IUnknown_QueryInterface(unk, &IID_IXMLDOMAttribute, (void**)attributeNode);
1354 IUnknown_Release(unk);
1355 }
1356
1357 return hr;
1358 }
1359
1360 static HRESULT WINAPI domelem_setAttributeNode(
1361 IXMLDOMElement *iface,
1362 IXMLDOMAttribute* attribute,
1363 IXMLDOMAttribute** old)
1364 {
1365 domelem *This = impl_from_IXMLDOMElement( iface );
1366 static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
1367 xmlChar *name, *value;
1368 BSTR nameW, prefix;
1369 xmlnode *attr_node;
1370 xmlAttrPtr attr;
1371 VARIANT valueW;
1372 HRESULT hr;
1373
1374 FIXME("(%p)->(%p %p): semi-stub\n", This, attribute, old);
1375
1376 if (!attribute) return E_INVALIDARG;
1377
1378 attr_node = get_node_obj((IXMLDOMNode*)attribute);
1379 if (!attr_node) return E_FAIL;
1380
1381 if (attr_node->parent)
1382 {
1383 WARN("attempt to add already used attribute\n");
1384 return E_FAIL;
1385 }
1386
1387 hr = IXMLDOMAttribute_get_nodeName(attribute, &nameW);
1388 if (hr != S_OK) return hr;
1389
1390 /* adding xmlns attribute doesn't change a tree or existing namespace definition */
1391 if (!strcmpW(nameW, xmlnsW))
1392 {
1393 SysFreeString(nameW);
1394 return DISP_E_UNKNOWNNAME;
1395 }
1396
1397 hr = IXMLDOMAttribute_get_nodeValue(attribute, &valueW);
1398 if (hr != S_OK)
1399 {
1400 SysFreeString(nameW);
1401 return hr;
1402 }
1403
1404 if (old) *old = NULL;
1405
1406 TRACE("attribute: %s=%s\n", debugstr_w(nameW), debugstr_w(V_BSTR(&valueW)));
1407
1408 hr = IXMLDOMAttribute_get_prefix(attribute, &prefix);
1409 if (hr == S_OK)
1410 {
1411 FIXME("namespaces not supported: %s\n", debugstr_w(prefix));
1412 SysFreeString(prefix);
1413 }
1414
1415 name = xmlchar_from_wchar(nameW);
1416 value = xmlchar_from_wchar(V_BSTR(&valueW));
1417
1418 if (!name || !value)
1419 {
1420 SysFreeString(nameW);
1421 VariantClear(&valueW);
1422 heap_free(name);
1423 heap_free(value);
1424 return E_OUTOFMEMORY;
1425 }
1426
1427 attr = xmlSetNsProp(get_element(This), NULL, name, value);
1428 if (attr)
1429 attr_node->parent = (IXMLDOMNode*)iface;
1430
1431 SysFreeString(nameW);
1432 VariantClear(&valueW);
1433 heap_free(name);
1434 heap_free(value);
1435
1436 return attr ? S_OK : E_FAIL;
1437 }
1438
1439 static HRESULT WINAPI domelem_removeAttributeNode(
1440 IXMLDOMElement *iface,
1441 IXMLDOMAttribute* domAttribute,
1442 IXMLDOMAttribute** attributeNode)
1443 {
1444 domelem *This = impl_from_IXMLDOMElement( iface );
1445 FIXME("(%p)->(%p %p)\n", This, domAttribute, attributeNode);
1446 return E_NOTIMPL;
1447 }
1448
1449 static HRESULT WINAPI domelem_getElementsByTagName(
1450 IXMLDOMElement *iface,
1451 BSTR tagName, IXMLDOMNodeList** resultList)
1452 {
1453 domelem *This = impl_from_IXMLDOMElement( iface );
1454 xmlChar *query;
1455 HRESULT hr;
1456 BOOL XPath;
1457
1458 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1459
1460 if (!tagName || !resultList) return E_INVALIDARG;
1461
1462 XPath = is_xpathmode(get_element(This)->doc);
1463 set_xpathmode(get_element(This)->doc, TRUE);
1464 query = tagName_to_XPath(tagName);
1465 hr = create_selection(get_element(This), query, resultList);
1466 xmlFree(query);
1467 set_xpathmode(get_element(This)->doc, XPath);
1468
1469 return hr;
1470 }
1471
1472 static HRESULT WINAPI domelem_normalize(
1473 IXMLDOMElement *iface )
1474 {
1475 domelem *This = impl_from_IXMLDOMElement( iface );
1476 FIXME("%p\n", This);
1477 return E_NOTIMPL;
1478 }
1479
1480 static const struct IXMLDOMElementVtbl domelem_vtbl =
1481 {
1482 domelem_QueryInterface,
1483 domelem_AddRef,
1484 domelem_Release,
1485 domelem_GetTypeInfoCount,
1486 domelem_GetTypeInfo,
1487 domelem_GetIDsOfNames,
1488 domelem_Invoke,
1489 domelem_get_nodeName,
1490 domelem_get_nodeValue,
1491 domelem_put_nodeValue,
1492 domelem_get_nodeType,
1493 domelem_get_parentNode,
1494 domelem_get_childNodes,
1495 domelem_get_firstChild,
1496 domelem_get_lastChild,
1497 domelem_get_previousSibling,
1498 domelem_get_nextSibling,
1499 domelem_get_attributes,
1500 domelem_insertBefore,
1501 domelem_replaceChild,
1502 domelem_removeChild,
1503 domelem_appendChild,
1504 domelem_hasChildNodes,
1505 domelem_get_ownerDocument,
1506 domelem_cloneNode,
1507 domelem_get_nodeTypeString,
1508 domelem_get_text,
1509 domelem_put_text,
1510 domelem_get_specified,
1511 domelem_get_definition,
1512 domelem_get_nodeTypedValue,
1513 domelem_put_nodeTypedValue,
1514 domelem_get_dataType,
1515 domelem_put_dataType,
1516 domelem_get_xml,
1517 domelem_transformNode,
1518 domelem_selectNodes,
1519 domelem_selectSingleNode,
1520 domelem_get_parsed,
1521 domelem_get_namespaceURI,
1522 domelem_get_prefix,
1523 domelem_get_baseName,
1524 domelem_transformNodeToObject,
1525 domelem_get_tagName,
1526 domelem_getAttribute,
1527 domelem_setAttribute,
1528 domelem_removeAttribute,
1529 domelem_getAttributeNode,
1530 domelem_setAttributeNode,
1531 domelem_removeAttributeNode,
1532 domelem_getElementsByTagName,
1533 domelem_normalize,
1534 };
1535
1536 static HRESULT domelem_get_qualified_item(const xmlNodePtr node, BSTR name, BSTR uri,
1537 IXMLDOMNode **item)
1538 {
1539 xmlAttrPtr attr;
1540 xmlChar *nameA;
1541 xmlChar *href;
1542
1543 TRACE("(%p)->(%s %s %p)\n", node, debugstr_w(name), debugstr_w(uri), item);
1544
1545 if (!name || !item) return E_INVALIDARG;
1546
1547 if (uri && *uri)
1548 {
1549 href = xmlchar_from_wchar(uri);
1550 if (!href) return E_OUTOFMEMORY;
1551 }
1552 else
1553 href = NULL;
1554
1555 nameA = xmlchar_from_wchar(name);
1556 if (!nameA)
1557 {
1558 heap_free(href);
1559 return E_OUTOFMEMORY;
1560 }
1561
1562 attr = xmlHasNsProp(node, nameA, href);
1563
1564 heap_free(nameA);
1565 heap_free(href);
1566
1567 if (!attr)
1568 {
1569 *item = NULL;
1570 return S_FALSE;
1571 }
1572
1573 *item = create_node((xmlNodePtr)attr);
1574
1575 return S_OK;
1576 }
1577
1578 static HRESULT domelem_get_named_item(const xmlNodePtr node, BSTR name, IXMLDOMNode **item)
1579 {
1580 xmlChar *nameA, *local, *prefix;
1581 BSTR uriW, localW;
1582 xmlNsPtr ns;
1583 HRESULT hr;
1584
1585 TRACE("(%p)->(%s %p)\n", node, debugstr_w(name), item );
1586
1587 nameA = xmlchar_from_wchar(name);
1588 local = xmlSplitQName2(nameA, &prefix);
1589 heap_free(nameA);
1590
1591 if (!local)
1592 return domelem_get_qualified_item(node, name, NULL, item);
1593
1594 /* try to get namespace uri for supplied qualified name */
1595 ns = xmlSearchNs(node->doc, node, prefix);
1596
1597 xmlFree(prefix);
1598
1599 if (!ns)
1600 {
1601 xmlFree(local);
1602 if (item) *item = NULL;
1603 return item ? S_FALSE : E_INVALIDARG;
1604 }
1605
1606 uriW = bstr_from_xmlChar(ns->href);
1607 localW = bstr_from_xmlChar(local);
1608 xmlFree(local);
1609
1610 TRACE("got qualified node %s, uri=%s\n", debugstr_w(localW), debugstr_w(uriW));
1611
1612 hr = domelem_get_qualified_item(node, localW, uriW, item);
1613
1614 SysFreeString(localW);
1615 SysFreeString(uriW);
1616
1617 return hr;
1618 }
1619
1620 static HRESULT domelem_set_named_item(xmlNodePtr node, IXMLDOMNode *newItem, IXMLDOMNode **namedItem)
1621 {
1622 xmlNodePtr nodeNew;
1623 xmlnode *ThisNew;
1624
1625 TRACE("(%p)->(%p %p)\n", node, newItem, namedItem );
1626
1627 if(!newItem)
1628 return E_INVALIDARG;
1629
1630 if(namedItem) *namedItem = NULL;
1631
1632 /* Must be an Attribute */
1633 ThisNew = get_node_obj( newItem );
1634 if(!ThisNew) return E_FAIL;
1635
1636 if(ThisNew->node->type != XML_ATTRIBUTE_NODE)
1637 return E_FAIL;
1638
1639 if(!ThisNew->node->parent)
1640 if(xmldoc_remove_orphan(ThisNew->node->doc, ThisNew->node) != S_OK)
1641 WARN("%p is not an orphan of %p\n", ThisNew->node, ThisNew->node->doc);
1642
1643 nodeNew = xmlAddChild(node, ThisNew->node);
1644
1645 if(namedItem)
1646 *namedItem = create_node( nodeNew );
1647 return S_OK;
1648 }
1649
1650 static HRESULT domelem_remove_qualified_item(xmlNodePtr node, BSTR name, BSTR uri, IXMLDOMNode **item)
1651 {
1652 xmlChar *nameA, *href;
1653 xmlAttrPtr attr;
1654
1655 TRACE("(%p)->(%s %s %p)\n", node, debugstr_w(name), debugstr_w(uri), item);
1656
1657 if (!name) return E_INVALIDARG;
1658
1659 if (uri && *uri)
1660 {
1661 href = xmlchar_from_wchar(uri);
1662 if (!href) return E_OUTOFMEMORY;
1663 }
1664 else
1665 href = NULL;
1666
1667 nameA = xmlchar_from_wchar(name);
1668 if (!nameA)
1669 {
1670 heap_free(href);
1671 return E_OUTOFMEMORY;
1672 }
1673
1674 attr = xmlHasNsProp(node, nameA, href);
1675
1676 heap_free(nameA);
1677 heap_free(href);
1678
1679 if (!attr)
1680 {
1681 if (item) *item = NULL;
1682 return S_FALSE;
1683 }
1684
1685 if (item)
1686 {
1687 xmlUnlinkNode( (xmlNodePtr) attr );
1688 xmldoc_add_orphan( attr->doc, (xmlNodePtr) attr );
1689 *item = create_node( (xmlNodePtr) attr );
1690 }
1691 else
1692 {
1693 if (xmlRemoveProp(attr) == -1)
1694 ERR("xmlRemoveProp failed\n");
1695 }
1696
1697 return S_OK;
1698 }
1699
1700 static HRESULT domelem_remove_named_item(xmlNodePtr node, BSTR name, IXMLDOMNode **item)
1701 {
1702 TRACE("(%p)->(%s %p)\n", node, debugstr_w(name), item);
1703 return domelem_remove_qualified_item(node, name, NULL, item);
1704 }
1705
1706 static HRESULT domelem_get_item(const xmlNodePtr node, LONG index, IXMLDOMNode **item)
1707 {
1708 xmlAttrPtr curr;
1709 LONG attrIndex;
1710
1711 TRACE("(%p)->(%d %p)\n", node, index, item);
1712
1713 *item = NULL;
1714
1715 if (index < 0)
1716 return S_FALSE;
1717
1718 curr = node->properties;
1719
1720 for (attrIndex = 0; attrIndex < index; attrIndex++) {
1721 if (curr->next == NULL)
1722 return S_FALSE;
1723 else
1724 curr = curr->next;
1725 }
1726
1727 *item = create_node( (xmlNodePtr) curr );
1728
1729 return S_OK;
1730 }
1731
1732 static HRESULT domelem_get_length(const xmlNodePtr node, LONG *length)
1733 {
1734 xmlAttrPtr first;
1735 xmlAttrPtr curr;
1736 LONG attrCount;
1737
1738 TRACE("(%p)->(%p)\n", node, length);
1739
1740 if( !length )
1741 return E_INVALIDARG;
1742
1743 first = node->properties;
1744 if (first == NULL) {
1745 *length = 0;
1746 return S_OK;
1747 }
1748
1749 curr = first;
1750 attrCount = 1;
1751 while (curr->next) {
1752 attrCount++;
1753 curr = curr->next;
1754 }
1755 *length = attrCount;
1756
1757 return S_OK;
1758 }
1759
1760 static HRESULT domelem_next_node(const xmlNodePtr node, LONG *iter, IXMLDOMNode **nextNode)
1761 {
1762 xmlAttrPtr curr;
1763 LONG i;
1764
1765 TRACE("(%p)->(%d: %p)\n", node, *iter, nextNode);
1766
1767 *nextNode = NULL;
1768
1769 curr = node->properties;
1770
1771 for (i = 0; i < *iter; i++) {
1772 if (curr->next == NULL)
1773 return S_FALSE;
1774 else
1775 curr = curr->next;
1776 }
1777
1778 (*iter)++;
1779 *nextNode = create_node((xmlNodePtr)curr);
1780
1781 return S_OK;
1782 }
1783
1784 static const struct nodemap_funcs domelem_attr_map = {
1785 domelem_get_named_item,
1786 domelem_set_named_item,
1787 domelem_remove_named_item,
1788 domelem_get_item,
1789 domelem_get_length,
1790 domelem_get_qualified_item,
1791 domelem_remove_qualified_item,
1792 domelem_next_node
1793 };
1794
1795 static const tid_t domelem_iface_tids[] = {
1796 IXMLDOMElement_tid,
1797 0
1798 };
1799
1800 static dispex_static_data_t domelem_dispex = {
1801 NULL,
1802 IXMLDOMElement_tid,
1803 NULL,
1804 domelem_iface_tids
1805 };
1806
1807 IUnknown* create_element( xmlNodePtr element )
1808 {
1809 domelem *This;
1810
1811 This = heap_alloc( sizeof *This );
1812 if ( !This )
1813 return NULL;
1814
1815 This->IXMLDOMElement_iface.lpVtbl = &domelem_vtbl;
1816 This->ref = 1;
1817
1818 init_xmlnode(&This->node, element, (IXMLDOMNode*)&This->IXMLDOMElement_iface, &domelem_dispex);
1819
1820 return (IUnknown*)&This->IXMLDOMElement_iface;
1821 }
1822
1823 #endif