1 /******************************************************************/
2 /* Implementation of XML document processing using MS DOM */
3 /* Author: Olivier Bertrand 2007 - 2013 */
4 /******************************************************************/
5 #include "my_global.h"
6 #include <stdio.h>
7 #if defined(_WIN32)
8 //#include <windows.h>
9 #if defined(MSX2)
10 #import "msxml2.dll" //Does not exist on Vista
11 #elif defined(MSX3)
12 #import "msxml3.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
13 #elif defined(MSX4)
14 #import "msxml4.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
15 #elif defined(MSX6)
16 #pragma warning(suppress : 4192)
17 #import "msxml6.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
18 #else // MSX4
19 #error MSX? is not defined
20 #endif // MSX
21 using namespace MSXML2;
22 #else
23 #error This is a Windows implementation only
24 #endif
25
26 #define NODE_TYPE_LIST
27
28 #include "global.h"
29 #include "plgdbsem.h"
30 #include "xobject.h"
31 #include "domdoc.h"
32
TestHr(PGLOBAL g,HRESULT hr)33 inline bool TestHr(PGLOBAL g, HRESULT hr)
34 {
35 if FAILED(hr) {
36 sprintf(g->Message, "%s, hr=%d", MSG(COM_ERROR), hr);
37 return true;
38 } else
39 return false;
40
41 } // end of TestHr
42
43 /******************************************************************/
44 /* Return a DOMDOC as a XMLDOC. */
45 /******************************************************************/
GetDomDoc(PGLOBAL g,char * nsl,char * nsdf,char * enc,PFBLOCK fp)46 PXDOC GetDomDoc(PGLOBAL g, char *nsl, char *nsdf,
47 char *enc, PFBLOCK fp)
48 {
49 return (PXDOC) new(g) DOMDOC(nsl, nsdf, enc, fp);
50 } // end of GetDomDoc
51
52 /***********************************************************************/
53 /* Close a loaded DOM XML file. */
54 /***********************************************************************/
CloseXMLFile(PGLOBAL g,PFBLOCK fp,bool all)55 void CloseXMLFile(PGLOBAL g, PFBLOCK fp, bool all)
56 {
57 PXBLOCK xp = (PXBLOCK)fp;
58
59 if (xp && xp->Count > 1 && !all) {
60 xp->Count--;
61 } else if (xp && xp->Count > 0) {
62 try {
63 if (xp->Docp)
64 xp->Docp->Release();
65
66 } catch(_com_error e) {
67 char *p = _com_util::ConvertBSTRToString(e.Description());
68 sprintf(g->Message, "%s %s", MSG(COM_ERROR), p);
69 delete[] p;
70 } catch(...) {}
71
72 CoUninitialize();
73 xp->Count = 0;
74 } // endif
75
76 } // end of CloseXMLFile
77
78 /* ------------------------ class DOMDOC ------------------------ */
79
80 /******************************************************************/
81 /* DOMDOC constructor. */
82 /******************************************************************/
DOMDOC(char * nsl,char * nsdf,char * enc,PFBLOCK fp)83 DOMDOC::DOMDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp)
84 : XMLDOCUMENT(nsl, nsdf, enc)
85 {
86 assert (!fp || fp->Type == TYPE_FB_XML);
87 Docp = (fp) ? ((PXBLOCK)fp)->Docp : (MSXML2::IXMLDOMDocumentPtr)NULL;
88 Nlist = NULL;
89 Hr = 0;
90 } // end of DOMDOC constructor
91
92 /******************************************************************/
93 /* Initialize XML parser and check library compatibility. */
94 /******************************************************************/
Initialize(PGLOBAL g,PCSZ entry,bool zipped)95 bool DOMDOC::Initialize(PGLOBAL g, PCSZ entry, bool zipped)
96 {
97 if (zipped && InitZip(g, entry))
98 return true;
99
100 if (TestHr(g, CoInitialize(NULL)))
101 return true;
102
103 if (TestHr(g, Docp.CreateInstance("msxml2.domdocument")))
104 return true;
105
106 return MakeNSlist(g);
107 } // end of Initialize
108
109 /******************************************************************/
110 /* Parse the XML file and construct node tree in memory. */
111 /******************************************************************/
ParseFile(PGLOBAL g,char * fn)112 bool DOMDOC::ParseFile(PGLOBAL g, char *fn)
113 {
114 bool b;
115
116 Docp->async = false;
117
118 if (zip) {
119 // Parse an in memory document
120 char *xdoc = GetMemDoc(g, fn);
121
122 // This is not equivalent to load for UTF8 characters
123 // It is why get node content is not the same
124 b = (xdoc) ? (bool)Docp->loadXML((_bstr_t)xdoc) : false;
125 } else
126 // Load the document
127 b = (bool)Docp->load((_bstr_t)fn);
128
129 if (!b)
130 return true;
131
132 return false;
133 } // end of ParseFile
134
135 /******************************************************************/
136 /* Create or reuse an Xblock for this document. */
137 /******************************************************************/
LinkXblock(PGLOBAL g,MODE m,int rc,char * fn)138 PFBLOCK DOMDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
139 {
140 PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
141 PXBLOCK xp = (PXBLOCK)PlugSubAlloc(g, NULL, sizeof(XBLOCK));
142
143 memset(xp, 0, sizeof(XBLOCK));
144 xp->Next = (PXBLOCK)dup->Openlist;
145 dup->Openlist = (PFBLOCK)xp;
146 xp->Type = TYPE_FB_XML;
147 xp->Fname = (LPCSTR)PlugSubAlloc(g, NULL, strlen(fn) + 1);
148 strcpy((char*)xp->Fname, fn);
149 xp->Count = 1;
150 xp->Length = (m == MODE_READ) ? 1 : 0;
151 xp->Docp = Docp;
152 xp->Retcode = rc;
153
154 // Return xp as a fp
155 return (PFBLOCK)xp;
156 } // end of LinkXblock
157
158 /******************************************************************/
159 /* Create the XML node. */
160 /******************************************************************/
NewDoc(PGLOBAL g,PCSZ ver)161 bool DOMDOC::NewDoc(PGLOBAL g, PCSZ ver)
162 {
163 char buf[64];
164 MSXML2::IXMLDOMProcessingInstructionPtr pip;
165
166 sprintf(buf, "version=\"%s\" encoding=\"%s\"", ver, Encoding);
167 pip = Docp->createProcessingInstruction("xml", buf);
168 return(TestHr(g, Docp->appendChild(pip)));
169 } // end of NewDoc
170
171 /******************************************************************/
172 /* Add a comment to the document node. */
173 /******************************************************************/
AddComment(PGLOBAL g,char * com)174 void DOMDOC::AddComment(PGLOBAL g, char *com)
175 {
176 TestHr(g, Docp->appendChild(Docp->createComment(com)));
177 } // end of AddComment
178
179 /******************************************************************/
180 /* Return the node class of the root of the document. */
181 /******************************************************************/
GetRoot(PGLOBAL g)182 PXNODE DOMDOC::GetRoot(PGLOBAL g)
183 {
184 MSXML2::IXMLDOMElementPtr root = Docp->documentElement;
185
186 if (root == NULL)
187 return NULL;
188
189 return new(g) DOMNODE(this, root);
190 } // end of GetRoot
191
192 /******************************************************************/
193 /* Create a new root element and return its class node. */
194 /******************************************************************/
NewRoot(PGLOBAL g,char * name)195 PXNODE DOMDOC::NewRoot(PGLOBAL g, char *name)
196 {
197 MSXML2::IXMLDOMElementPtr ep = Docp->createElement(name);
198
199 if (ep == NULL || TestHr(g, Docp->appendChild(ep)))
200 return NULL;
201
202 return new(g) DOMNODE(this, ep);
203 } // end of NewRoot
204
205 /******************************************************************/
206 /* Return a void DOMNODE node class. */
207 /******************************************************************/
NewPnode(PGLOBAL g,char * name)208 PXNODE DOMDOC::NewPnode(PGLOBAL g, char *name)
209 {
210 MSXML2::IXMLDOMElementPtr root = NULL;
211
212 if (name)
213 if ((root = Docp->createElement(name)) == NULL)
214 return NULL;
215
216 return new(g) DOMNODE(this, root);
217 } // end of NewPnode
218
219 /******************************************************************/
220 /* Return a void DOMATTR node class. */
221 /******************************************************************/
NewPattr(PGLOBAL g)222 PXATTR DOMDOC::NewPattr(PGLOBAL g)
223 {
224 return new(g) DOMATTR(this, NULL);
225 } // end of NewPattr
226
227 /******************************************************************/
228 /* Return a void DOMATTR node class. */
229 /******************************************************************/
NewPlist(PGLOBAL g)230 PXLIST DOMDOC::NewPlist(PGLOBAL g)
231 {
232 return new(g) DOMNODELIST(this, NULL);
233 } // end of NewPlist
234
235 /******************************************************************/
236 /* Dump the node tree to a new XML file. */
237 /******************************************************************/
DumpDoc(PGLOBAL g,char * ofn)238 int DOMDOC::DumpDoc(PGLOBAL g, char *ofn)
239 {
240 int rc = 0;
241
242 try {
243 Docp->save(ofn);
244 } catch(_com_error e) {
245 sprintf(g->Message, "%s: %s", MSG(COM_ERROR),
246 _com_util::ConvertBSTRToString(e.Description()));
247 rc = -1;
248 } catch(...) {}
249
250 return rc;
251 } // end of Dump
252
253 /******************************************************************/
254 /* Free the document, cleanup the XML library, and */
255 /* debug memory for regression tests. */
256 /******************************************************************/
CloseDoc(PGLOBAL g,PFBLOCK xp)257 void DOMDOC::CloseDoc(PGLOBAL g, PFBLOCK xp)
258 {
259 CloseXMLFile(g, xp, false);
260 CloseZip();
261 } // end of Close
262
263 /* ----------------------- class DOMNODE ------------------------ */
264
265 /******************************************************************/
266 /* DOMNODE constructor. */
267 /******************************************************************/
DOMNODE(PXDOC dp,MSXML2::IXMLDOMNodePtr np)268 DOMNODE::DOMNODE(PXDOC dp, MSXML2::IXMLDOMNodePtr np) : XMLNODE(dp)
269 {
270 Docp = ((PDOMDOC)dp)->Docp;
271 Nodep = np;
272 Ws = NULL;
273 Len = 0;
274 Zip = (bool)dp->zip;
275 } // end of DOMNODE constructor
276
277 /******************************************************************/
278 /* Return the node name. */
279 /******************************************************************/
GetName(PGLOBAL g)280 char *DOMNODE::GetName(PGLOBAL g)
281 {
282 if (!WideCharToMultiByte(CP_ACP, 0, Nodep->nodeName, -1,
283 Name, sizeof(Name), NULL, NULL)) {
284 strcpy(g->Message, MSG(NAME_CONV_ERR));
285 return NULL;
286 } // endif
287
288 return Name;
289 } // end of GetName
290
291 /******************************************************************/
292 /* Return the node class of next sibling of the node. */
293 /******************************************************************/
GetNext(PGLOBAL g)294 PXNODE DOMNODE::GetNext(PGLOBAL g)
295 {
296 if (Nodep->nextSibling == NULL)
297 Next = NULL;
298 else // if (!Next)
299 Next = new(g) DOMNODE(Doc, Nodep->nextSibling);
300
301 return Next;
302 } // end of GetNext
303
304 /******************************************************************/
305 /* Return the node class of first children of the node. */
306 /******************************************************************/
GetChild(PGLOBAL g)307 PXNODE DOMNODE::GetChild(PGLOBAL g)
308 {
309 if (Nodep->firstChild == NULL)
310 Children = NULL;
311 else // if (!Children)
312 Children = new(g) DOMNODE(Doc, Nodep->firstChild);
313
314 return Children;
315 } // end of GetChild
316
317 /******************************************************************/
318 /* Return the content of a node and subnodes. */
319 /******************************************************************/
GetContent(PGLOBAL g,char * buf,int len)320 RCODE DOMNODE::GetContent(PGLOBAL g, char *buf, int len)
321 {
322 RCODE rc = RC_OK;
323
324 // Nodep can be null for a missing HTML table column
325 if (Nodep) {
326 if (Zip) {
327 strcpy(buf, Nodep->text);
328 } else if (!WideCharToMultiByte(CP_UTF8, 0, Nodep->text, -1,
329 buf, len, NULL, NULL)) {
330 DWORD lsr = GetLastError();
331
332 switch (lsr) {
333 case 0:
334 case ERROR_INSUFFICIENT_BUFFER: // 122L
335 sprintf(g->Message, "Truncated %s content", GetName(g));
336 rc = RC_INFO;
337 break;
338 case ERROR_NO_UNICODE_TRANSLATION: // 1113L
339 sprintf(g->Message, "Invalid character(s) in %s content",
340 GetName(g));
341 rc = RC_INFO;
342 break;
343 default:
344 sprintf(g->Message, "System error getting %s content",
345 GetName(g));
346 rc = RC_FX;
347 break;
348 } // endswitch
349
350 } // endif
351
352 } else
353 *buf = '\0';
354
355 return rc;
356 } // end of GetContent
357
358 /******************************************************************/
359 /* Set the text content of an attribute. */
360 /******************************************************************/
SetContent(PGLOBAL g,char * txtp,int len)361 bool DOMNODE::SetContent(PGLOBAL g, char *txtp, int len)
362 {
363 bool rc;
364 BSTR val;
365
366 if (len > Len || !Ws) {
367 Ws = (WCHAR*)PlugSubAlloc(g, NULL, (len + 1) * 2);
368 Len = len;
369 } // endif len
370
371 if (!MultiByteToWideChar(CP_UTF8, 0, txtp, strlen(txtp) + 1,
372 Ws, Len + 1)) {
373 sprintf(g->Message, MSG(WS_CONV_ERR), txtp);
374 return true;
375 } // endif
376
377 val = SysAllocString(Ws);
378 rc = TestHr(g, Nodep->put_text(val));
379 SysFreeString(val);
380 return rc;
381 } // end of SetContent
382
383 /******************************************************************/
384 /* Return a clone of this node. */
385 /******************************************************************/
Clone(PGLOBAL g,PXNODE np)386 PXNODE DOMNODE::Clone(PGLOBAL g, PXNODE np)
387 {
388 if (np) {
389 ((PDOMNODE)np)->Nodep = Nodep;
390 return np;
391 } else
392 return new(g) DOMNODE(Doc, Nodep);
393
394 } // end of Clone
395
396 /******************************************************************/
397 /* Return the list of all or matching children that are elements.*/
398 /******************************************************************/
GetChildElements(PGLOBAL g,char * xp,PXLIST lp)399 PXLIST DOMNODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp)
400 {
401 MSXML2::IXMLDOMNodeListPtr dnlp;
402
403 if (xp) {
404 if (Nodep->nodeType == MSXML2::NODE_ELEMENT) {
405 MSXML2::IXMLDOMElementPtr ep = Nodep;
406 dnlp = ep->getElementsByTagName(xp);
407 } else
408 return NULL;
409
410 } else
411 dnlp = Nodep->childNodes;
412
413 if (lp) {
414 ((PDOMLIST)lp)->Listp = dnlp;
415 return lp;
416 } else
417 return new(g) DOMNODELIST(Doc, dnlp);
418
419 } // end of GetChildElements
420
421 /******************************************************************/
422 /* Return the list of nodes verifying the passed Xapth. */
423 /******************************************************************/
SelectNodes(PGLOBAL g,char * xp,PXLIST lp)424 PXLIST DOMNODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp)
425 {
426 MSXML2::IXMLDOMNodeListPtr dnlp = Nodep->selectNodes(xp);
427
428 if (lp) {
429 ((PDOMLIST)lp)->Listp = dnlp;
430 return lp;
431 } else
432 return new(g) DOMNODELIST(Doc, dnlp);
433
434 } // end of SelectNodes
435
436 /******************************************************************/
437 /* Return the first node verifying the passed Xapth. */
438 /******************************************************************/
SelectSingleNode(PGLOBAL g,char * xp,PXNODE np)439 PXNODE DOMNODE::SelectSingleNode(PGLOBAL g, char *xp, PXNODE np)
440 {
441 try {
442 MSXML2::IXMLDOMNodePtr dnp = Nodep->selectSingleNode(xp);
443
444 if (dnp) {
445 if (np) {
446 ((PDOMNODE)np)->Nodep = dnp;
447 return np;
448 } else
449 return new(g) DOMNODE(Doc, dnp);
450
451 } // endif dnp
452
453 } catch(_com_error e) {
454 sprintf(g->Message, "%s: %s", MSG(COM_ERROR),
455 _com_util::ConvertBSTRToString(e.Description()));
456 } catch(...) {}
457
458 return NULL;
459 } // end of SelectSingleNode
460
461 /******************************************************************/
462 /* Return the node attribute with the specified name. */
463 /******************************************************************/
GetAttribute(PGLOBAL g,char * name,PXATTR ap)464 PXATTR DOMNODE::GetAttribute(PGLOBAL g, char *name, PXATTR ap)
465 {
466 MSXML2::IXMLDOMElementPtr ep;
467 MSXML2::IXMLDOMNamedNodeMapPtr nmp;
468 MSXML2::IXMLDOMAttributePtr atp;
469
470 if (name) {
471 ep = Nodep;
472 atp = ep->getAttributeNode(name);
473 nmp = NULL;
474 } else {
475 nmp = Nodep->Getattributes();
476 atp = nmp->Getitem(0);
477 } // endif name
478
479 if (atp) {
480 if (ap) {
481 ((PDOMATTR)ap)->Atrp = atp;
482 ((PDOMATTR)ap)->Nmp = nmp;
483 ((PDOMATTR)ap)->K = 0;
484 return ap;
485 } else
486 return new(g) DOMATTR(Doc, atp, nmp);
487
488 } else
489 return NULL;
490
491 } // end of GetAttribute
492
493 /******************************************************************/
494 /* Add a new element child node to this node and return it. */
495 /******************************************************************/
AddChildNode(PGLOBAL g,PCSZ name,PXNODE np)496 PXNODE DOMNODE::AddChildNode(PGLOBAL g, PCSZ name, PXNODE np)
497 {
498 const char *p, *pn;
499 // char *p, *pn, *epf, *pf = NULL;
500 MSXML2::IXMLDOMNodePtr ep;
501 // _bstr_t uri((wchar_t*)NULL);
502
503 #if 0
504 // Is a prefix specified ?
505 if ((p = strchr(name, ':'))) {
506 pf = BufAlloc(g, name, p - name);
507
508 // Is it the pseudo default prefix
509 if (Doc->DefNs && !strcmp(pf, Doc->DefNs)) {
510 name = p + 1; // Suppress it from name
511 pf = NULL; // No real prefix
512 } // endif DefNs
513
514 } // endif p
515
516 // Look for matching namespace URI in context
517 for (ep = Nodep; ep; ep = ep->parentNode) {
518 epf = (_bstr_t)ep->prefix;
519
520 if ((!pf && !epf) || (pf && epf && !strcmp(pf, epf))) {
521 uri = Nodep->namespaceURI;
522 break;
523 } // endif
524
525 } // endfor ep
526
527 if ((wchar_t*)uri == NULL) {
528 if (!pf)
529 pf = Doc->DefNs;
530
531 // Look for the namespace URI corresponding to this node
532 if (pf)
533 for (PNS nsp = Doc->Namespaces; nsp; nsp = nsp->Next)
534 if (!strcmp(pf, nsp->Prefix)) {
535 uri = nsp->Uri;
536 break;
537 } // endfor nsp
538
539 } // endif pns
540 #endif // 0
541
542 // If name has the format m[n] only m is taken as node name
543 if ((p = strchr(name, '[')))
544 pn = BufAlloc(g, name, (int)(p - name));
545 else
546 pn = name;
547
548 // Construct the element node with eventual namespace
549 // ep = Docp->createNode(_variant_t("Element"), pn, uri);
550 ep = Docp->createElement(pn);
551
552 _bstr_t pfx = ep->prefix;
553 _bstr_t uri = ep->namespaceURI;
554
555 if (ep == NULL || TestHr(g, Nodep->appendChild(ep)))
556 return NULL;
557
558 if (np)
559 ((PDOMNODE)np)->Nodep = ep;
560 else
561 np = new(g) DOMNODE(Doc, ep);
562
563 return NewChild(np);
564 } // end of AddChildNode
565
566 /******************************************************************/
567 /* Add a new property to this node and return it. */
568 /******************************************************************/
AddProperty(PGLOBAL g,char * name,PXATTR ap)569 PXATTR DOMNODE::AddProperty(PGLOBAL g, char *name, PXATTR ap)
570 {
571 MSXML2::IXMLDOMAttributePtr atp = Docp->createAttribute(name);
572
573 if (atp) {
574 MSXML2::IXMLDOMElementPtr ep = Nodep;
575 ep->setAttributeNode(atp);
576
577 if (ap) {
578 ((PDOMATTR)ap)->Atrp = atp;
579 return ap;
580 } else
581 return new(g) DOMATTR(Doc, atp);
582
583 } else
584 return NULL;
585
586 } // end of AddProperty
587
588 /******************************************************************/
589 /* Add a new text node to this node. */
590 /******************************************************************/
AddText(PGLOBAL g,PCSZ txtp)591 void DOMNODE::AddText(PGLOBAL g, PCSZ txtp)
592 {
593 MSXML2::IXMLDOMTextPtr tp= Docp->createTextNode((_bstr_t)txtp);
594
595 if (tp != NULL)
596 TestHr(g, Nodep->appendChild(tp));
597
598 } // end of AddText
599
600 /******************************************************************/
601 /* Remove a child node from this node. */
602 /******************************************************************/
DeleteChild(PGLOBAL g,PXNODE dnp)603 void DOMNODE::DeleteChild(PGLOBAL g, PXNODE dnp)
604 {
605 TestHr(g, Nodep->removeChild(((PDOMNODE)dnp)->Nodep));
606 // ((PDOMNODE)dnp)->Nodep->Release(); bad idea, causes a crash
607 Delete(dnp);
608 } // end of DeleteChild
609
610 /* --------------------- class DOMNODELIST ---------------------- */
611
612 /******************************************************************/
613 /* DOMNODELIST constructor. */
614 /******************************************************************/
DOMNODELIST(PXDOC dp,MSXML2::IXMLDOMNodeListPtr lp)615 DOMNODELIST::DOMNODELIST(PXDOC dp, MSXML2::IXMLDOMNodeListPtr lp)
616 : XMLNODELIST(dp)
617 {
618 Listp = lp;
619 } // end of DOMNODELIST constructor
620
621 /******************************************************************/
622 /* Return the nth element of the list. */
623 /******************************************************************/
GetItem(PGLOBAL g,int n,PXNODE np)624 PXNODE DOMNODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
625 {
626 if (Listp == NULL || Listp->length <= n)
627 return NULL;
628
629 if (np) {
630 ((PDOMNODE)np)->Nodep = Listp->item[n];
631 return np;
632 } else
633 return new(g) DOMNODE(Doc, Listp->item[n]);
634
635 } // end of GetItem
636
637 /******************************************************************/
638 /* Reset the pointer on the deleted item. */
639 /******************************************************************/
DropItem(PGLOBAL g,int n)640 bool DOMNODELIST::DropItem(PGLOBAL g, int n)
641 {
642 if (Listp == NULL || Listp->length < n)
643 return true;
644
645 //Listp->item[n] = NULL; La propri�t� n'a pas de m�thode 'set'
646 return false;
647 } // end of DeleteItem
648
649 /* ----------------------- class DOMATTR ------------------------ */
650
651 /******************************************************************/
652 /* DOMATTR constructor. */
653 /******************************************************************/
DOMATTR(PXDOC dp,MSXML2::IXMLDOMAttributePtr ap,MSXML2::IXMLDOMNamedNodeMapPtr nmp)654 DOMATTR::DOMATTR(PXDOC dp, MSXML2::IXMLDOMAttributePtr ap,
655 MSXML2::IXMLDOMNamedNodeMapPtr nmp)
656 : XMLATTRIBUTE(dp)
657 {
658 Atrp = ap;
659 Nmp = nmp;
660 Ws = NULL;
661 Len = 0;
662 K = 0;
663 } // end of DOMATTR constructor
664
665 /******************************************************************/
666 /* Return the attribute name. */
667 /******************************************************************/
GetName(PGLOBAL g)668 char *DOMATTR::GetName(PGLOBAL g)
669 {
670 if (!WideCharToMultiByte(CP_ACP, 0, Atrp->nodeName, -1,
671 Name, sizeof(Name), NULL, NULL)) {
672 strcpy(g->Message, MSG(NAME_CONV_ERR));
673 return NULL;
674 } // endif
675
676 return Name;
677 } // end of GetName
678
679 /******************************************************************/
680 /* Return the next attribute node. */
681 /* This funtion is implemented as needed by XMLColumns. */
682 /******************************************************************/
GetNext(PGLOBAL g)683 PXATTR DOMATTR::GetNext(PGLOBAL g)
684 {
685 if (!Nmp)
686 return NULL;
687
688 if (++K >= Nmp->Getlength()) {
689 Nmp->reset();
690 Nmp = NULL;
691 K = 0;
692 return NULL;
693 } // endif K
694
695 Atrp = Nmp->Getitem(K);
696 return this;
697 } // end of GetNext
698
699 /******************************************************************/
700 /* Return the content of a node and subnodes. */
701 /******************************************************************/
GetText(PGLOBAL g,char * buf,int len)702 RCODE DOMATTR::GetText(PGLOBAL g, char *buf, int len)
703 {
704 RCODE rc = RC_OK;
705
706 if (!WideCharToMultiByte(CP_UTF8, 0, Atrp->text, -1,
707 buf, len, NULL, NULL)) {
708 DWORD lsr = GetLastError();
709
710 switch (lsr) {
711 case 0:
712 case ERROR_INSUFFICIENT_BUFFER: // 122L
713 sprintf(g->Message, "Truncated %s content", GetName(g));
714 rc = RC_INFO;
715 break;
716 case ERROR_NO_UNICODE_TRANSLATION: // 1113L
717 sprintf(g->Message, "Invalid character(s) in %s content",
718 GetName(g));
719 rc = RC_INFO;
720 break;
721 default:
722 sprintf(g->Message, "System error getting %s content",
723 GetName(g));
724 rc = RC_FX;
725 break;
726 } // endswitch
727
728 } // endif
729
730 return rc;
731 } // end of GetText
732
733 /******************************************************************/
734 /* Set the text content of an attribute. */
735 /******************************************************************/
SetText(PGLOBAL g,char * txtp,int len)736 bool DOMATTR::SetText(PGLOBAL g, char *txtp, int len)
737 {
738 bool rc;
739 BSTR val;
740
741 if (len > Len || !Ws) {
742 Ws = (WCHAR*)PlugSubAlloc(g, NULL, (len + 1) * 2);
743 Len = len;
744 } // endif len
745
746 if (!MultiByteToWideChar(CP_UTF8, 0, txtp, strlen(txtp) + 1,
747 Ws, Len + 1)) {
748 sprintf(g->Message, MSG(WS_CONV_ERR), txtp);
749 return true;
750 } // endif
751
752 val = SysAllocString(Ws);
753 rc = TestHr(g, Atrp->put_text(val));
754 SysFreeString(val);
755 return rc;
756 } // end of SetText
757