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