1 mike 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
8 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
13 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
18 **
19 ** See the Apache 2 License for the specific language governing permissions
20 ** and limitations under the License.
21 **
22 mike 1.1 **==============================================================================
23 */
24
25 #include "xmlcxx.h"
26 #include <xml/xml.h>
27 #include <base/buf.h>
28 #include <vector>
29 #include <memory.h>
30 #include <cctype>
31
32 using namespace std;
33
34 //==============================================================================
35 //
36 // class XMLElement
37 //
38 //==============================================================================
39
40 XMLCXX_BEGIN
41
42 class XMLElementRep
43 mike 1.1 {
44 public:
45 XML_Elem elem;
46 };
47
48 XMLElement::XMLElement()
49 {
50 _rep = new XMLElementRep;
51 Clear();
52 }
53
54 XMLElement::XMLElement(const XMLElement& x)
55 {
56 _rep = new XMLElementRep;
57 memcpy(_rep, x._rep, sizeof(XMLElementRep));
58 }
59
60 XMLElement::~XMLElement()
61 {
62 delete _rep;
63 }
64 mike 1.1
65 XMLElement& XMLElement::operator=(const XMLElement& x)
66 {
67 if (&x != this)
68 memcpy(_rep, x._rep, sizeof(XMLElementRep));
69
70 return *this;
71 }
72
73 void XMLElement::Clear()
74 {
75 // Element will have XMLElement::NONE type.
76 memset(_rep, 0, sizeof(XMLElementRep));
77 }
78
79 XMLElement::Type XMLElement::GetType() const
80 {
81 switch (_rep->elem.type)
82 {
83 case XML_NONE:
84 return NONE;
85 mike 1.1 case XML_START:
86 return START;
87 case XML_END:
88 return END;
89 case XML_CHARS:
90 return CHARS;
91 case XML_INSTRUCTION:
92 return INSTRUCTION;
93 case XML_COMMENT:
94 return COMMENT;
95 default:
96 return NONE;
97 }
98 }
99
100 const char* XMLElement::GetData() const
101 {
102 return _rep->elem.data ? _rep->elem.data : "";
103 }
104
105 size_t XMLElement::GetAttributeCount() const
106 mike 1.1 {
107 return _rep->elem.attrsSize;
108 }
109
110 const char* XMLElement::GetAttributeName(size_t index) const
111 {
112 if (index < _rep->elem.attrsSize)
113 return _rep->elem.attrs[index].name;
114 else
115 return NULL;
116 }
117
118 const char* XMLElement::GetAttributeValue(size_t index) const
119 {
120 if (index < _rep->elem.attrsSize)
121 return _rep->elem.attrs[index].value;
122 else
123 return NULL;
124 }
125
126 const char* XMLElement::FindAttributeValue(const char* name) const
127 mike 1.1 {
128 for (size_t i = 0; i < _rep->elem.attrsSize; i++)
129 {
130 if (strcmp(_rep->elem.attrs[i].name, name) == 0)
131 return _rep->elem.attrs[i].value;
132 }
133
134 // Not found!
135 return NULL;
136 }
137
138 void XMLElement::Dump() const
139 {
140 XML_Elem_Dump(&_rep->elem);
141 }
142
143 XMLCXX_END
144
145 //==============================================================================
146 //
147 // class XMLReader
148 mike 1.1 //
149 //==============================================================================
150
151 XMLCXX_BEGIN
152
153 class XMLReaderRep
154 {
155 public:
156 vector<char> text;
157 XML xml;
158
159 XMLReaderRep()
160 {
161 text.push_back('\0');
162 XML_Init(&xml);
163 }
164
165 void SetText(const char* text_)
166 {
167 text.clear();
168 text.insert(text.end(), text_, text_ + strlen(text_));
169 mike 1.1 text.push_back('\0');
170 XML_SetText(&xml, &text[0]);
171 }
172 };
173
174 XMLReader::XMLReader()
175 {
176 _rep = new XMLReaderRep;
177 }
178
179 XMLReader::XMLReader(const char* text)
180 {
181 _rep = new XMLReaderRep;
182 _rep->SetText(text);
183 }
184
185 XMLReader::~XMLReader()
186 {
187 delete _rep;
188 }
189
190 mike 1.1 size_t XMLReader::GetLineNumber() const
191 {
192 return _rep->xml.line;
193 }
194
195 void XMLReader::SetText(const char* text)
196 {
197 _rep->SetText(text);
198 }
199
200 bool XMLReader::GetNext(XMLElement& elem)
201 {
202 return XML_Next(&_rep->xml, &elem._rep->elem) == 0 ? true : false;
203 }
204
205 bool XMLReader::Skip()
206 {
207 return XML_Skip(&_rep->xml) == 0 ? true : false;
208 }
209
210 bool XMLReader::PutBack(XMLElement& elem)
211 mike 1.1 {
212 return XML_PutBack(&_rep->xml, &elem._rep->elem) == 0 ? true : false;
213 }
214
215 void XMLReader::Dump() const
216 {
217 XML_Dump(&_rep->xml);
218 }
219
220 string XMLReader::GetErrorMessage() const
221 {
222 char buf[512];
223 XML_FormatError(&_rep->xml, buf, sizeof(buf));
224 return string(buf);
225 }
226
227 void XMLReader::GetErrorMessage(char* buffer, size_t size)
228 {
229 XML_FormatError(&_rep->xml, buffer, size);
230 }
231
232 mike 1.1 bool XMLReader::GetError() const
233 {
234 return _rep->xml.status == -1;
235 }
236
237 bool XMLReader::RegisterNameSpace(char id, const char* uri)
238 {
239 return XML_RegisterNameSpace(&_rep->xml, id, uri) == 0 ? true : false;
240 }
241
242 XMLCXX_END
243
244 //==============================================================================
245 //
246 // class XMLWriter
247 //
248 //==============================================================================
249
250 XMLCXX_BEGIN
251
252 class XMLWriterRep
253 mike 1.1 {
254 public:
255 Buf buf;
256 bool enableLineSeparators;
257
258 XMLWriterRep() : enableLineSeparators(false)
259 {
260 Buf_Init(&buf, 4096);
261 }
262
263 ~XMLWriterRep()
264 {
265 Buf_Destroy(&buf);
266 }
267 };
268
269 static const struct
270 {
271 const char* str;
272 size_t len;
273 }
274 mike 1.1 _encode[256] =
275 {
276 { "�", sizeof("�")-1 },
277 { "", sizeof("")-1 },
278 { "", sizeof("")-1 },
279 { "", sizeof("")-1 },
280 { "", sizeof("")-1 },
281 { "", sizeof("")-1 },
282 { "", sizeof("")-1 },
283 { "", sizeof("")-1 },
284 { "", sizeof("")-1 },
285 { "	", sizeof("	")-1 },
286 { " ", sizeof(" ")-1 },
287 { "", sizeof("")-1 },
288 { "", sizeof("")-1 },
289 { " ", sizeof(" ")-1 },
290 { "", sizeof("")-1 },
291 { "", sizeof("")-1 },
292 { "", sizeof("")-1 },
293 { "", sizeof("")-1 },
294 { "", sizeof("")-1 },
295 mike 1.1 { "", sizeof("")-1 },
296 { "", sizeof("")-1 },
297 { "", sizeof("")-1 },
298 { "", sizeof("")-1 },
299 { "", sizeof("")-1 },
300 { "", sizeof("")-1 },
301 { "", sizeof("")-1 },
302 { "", sizeof("")-1 },
303 { "", sizeof("")-1 },
304 { "", sizeof("")-1 },
305 { "", sizeof("")-1 },
306 { "", sizeof("")-1 },
307 { "", sizeof("")-1 },
308 { " ", sizeof(" ")-1 },
309 { "!", sizeof("!")-1 },
310 { """, sizeof(""")-1 },
311 { "#", sizeof("#")-1 },
312 { "$", sizeof("$")-1 },
313 { "%", sizeof("%")-1 },
314 { "&", sizeof("&")-1 },
315 { "'", sizeof("'")-1 },
316 mike 1.1 { "(", sizeof("(")-1 },
317 { ")", sizeof(")")-1 },
318 { "*", sizeof("*")-1 },
319 { "+", sizeof("+")-1 },
320 { ",", sizeof(",")-1 },
321 { "-", sizeof("-")-1 },
322 { ".", sizeof(".")-1 },
323 { "/", sizeof("/")-1 },
324 { "0", sizeof("0")-1 },
325 { "1", sizeof("1")-1 },
326 { "2", sizeof("2")-1 },
327 { "3", sizeof("3")-1 },
328 { "4", sizeof("4")-1 },
329 { "5", sizeof("5")-1 },
330 { "6", sizeof("6")-1 },
331 { "7", sizeof("7")-1 },
332 { "8", sizeof("8")-1 },
333 { "9", sizeof("9")-1 },
334 { ":", sizeof(":")-1 },
335 { ";", sizeof(";")-1 },
336 { "<", sizeof("<")-1 },
337 mike 1.1 { "=", sizeof("=")-1 },
338 { ">", sizeof(">")-1 },
339 { "?", sizeof("?")-1 },
340 { "@", sizeof("@")-1 },
341 { "A", sizeof("A")-1 },
342 { "B", sizeof("B")-1 },
343 { "C", sizeof("C")-1 },
344 { "D", sizeof("D")-1 },
345 { "E", sizeof("E")-1 },
346 { "F", sizeof("F")-1 },
347 { "G", sizeof("G")-1 },
348 { "H", sizeof("H")-1 },
349 { "I", sizeof("I")-1 },
350 { "J", sizeof("J")-1 },
351 { "K", sizeof("K")-1 },
352 { "L", sizeof("L")-1 },
353 { "M", sizeof("M")-1 },
354 { "N", sizeof("N")-1 },
355 { "O", sizeof("O")-1 },
356 { "P", sizeof("P")-1 },
357 { "Q", sizeof("Q")-1 },
358 mike 1.1 { "R", sizeof("R")-1 },
359 { "S", sizeof("S")-1 },
360 { "T", sizeof("T")-1 },
361 { "U", sizeof("U")-1 },
362 { "V", sizeof("V")-1 },
363 { "W", sizeof("W")-1 },
364 { "X", sizeof("X")-1 },
365 { "Y", sizeof("Y")-1 },
366 { "Z", sizeof("Z")-1 },
367 { "[", sizeof("[")-1 },
368 { "\\", sizeof("\\")-1 },
369 { "]", sizeof("]")-1 },
370 { "^", sizeof("^")-1 },
371 { "_", sizeof("_")-1 },
372 { "`", sizeof("`")-1 },
373 { "a", sizeof("a")-1 },
374 { "b", sizeof("b")-1 },
375 { "c", sizeof("c")-1 },
376 { "d", sizeof("d")-1 },
377 { "e", sizeof("e")-1 },
378 { "f", sizeof("f")-1 },
379 mike 1.1 { "g", sizeof("g")-1 },
380 { "h", sizeof("h")-1 },
381 { "i", sizeof("i")-1 },
382 { "j", sizeof("j")-1 },
383 { "k", sizeof("k")-1 },
384 { "l", sizeof("l")-1 },
385 { "m", sizeof("m")-1 },
386 { "n", sizeof("n")-1 },
387 { "o", sizeof("o")-1 },
388 { "p", sizeof("p")-1 },
389 { "q", sizeof("q")-1 },
390 { "r", sizeof("r")-1 },
391 { "s", sizeof("s")-1 },
392 { "t", sizeof("t")-1 },
393 { "u", sizeof("u")-1 },
394 { "v", sizeof("v")-1 },
395 { "w", sizeof("w")-1 },
396 { "x", sizeof("x")-1 },
397 { "y", sizeof("y")-1 },
398 { "z", sizeof("z")-1 },
399 { "{", sizeof("{")-1 },
400 mike 1.1 { "|", sizeof("|")-1 },
401 { "}", sizeof("}")-1 },
402 { "~", sizeof("~")-1 },
403 { "", sizeof("")-1 },
404 { "€", sizeof("€")-1 },
405 { "", sizeof("")-1 },
406 { "‚", sizeof("‚")-1 },
407 { "ƒ", sizeof("ƒ")-1 },
408 { "„", sizeof("„")-1 },
409 { "…", sizeof("…")-1 },
410 { "†", sizeof("†")-1 },
411 { "‡", sizeof("‡")-1 },
412 { "ˆ", sizeof("ˆ")-1 },
413 { "‰", sizeof("‰")-1 },
414 { "Š", sizeof("Š")-1 },
415 { "‹", sizeof("‹")-1 },
416 { "Œ", sizeof("Œ")-1 },
417 { "", sizeof("")-1 },
418 { "Ž", sizeof("Ž")-1 },
419 { "", sizeof("")-1 },
420 { "", sizeof("")-1 },
421 mike 1.1 { "‘", sizeof("‘")-1 },
422 { "’", sizeof("’")-1 },
423 { "“", sizeof("“")-1 },
424 { "”", sizeof("”")-1 },
425 { "•", sizeof("•")-1 },
426 { "–", sizeof("–")-1 },
427 { "—", sizeof("—")-1 },
428 { "˜", sizeof("˜")-1 },
429 { "™", sizeof("™")-1 },
430 { "š", sizeof("š")-1 },
431 { "›", sizeof("›")-1 },
432 { "œ", sizeof("œ")-1 },
433 { "", sizeof("")-1 },
434 { "ž", sizeof("ž")-1 },
435 { "Ÿ", sizeof("Ÿ")-1 },
436 { " ", sizeof(" ")-1 },
437 { "¡", sizeof("¡")-1 },
438 { "¢", sizeof("¢")-1 },
439 { "£", sizeof("£")-1 },
440 { "¤", sizeof("¤")-1 },
441 { "¥", sizeof("¥")-1 },
442 mike 1.1 { "¦", sizeof("¦")-1 },
443 { "§", sizeof("§")-1 },
444 { "¨", sizeof("¨")-1 },
445 { "©", sizeof("©")-1 },
446 { "ª", sizeof("ª")-1 },
447 { "«", sizeof("«")-1 },
448 { "¬", sizeof("¬")-1 },
449 { "­", sizeof("­")-1 },
450 { "®", sizeof("®")-1 },
451 { "¯", sizeof("¯")-1 },
452 { "°", sizeof("°")-1 },
453 { "±", sizeof("±")-1 },
454 { "²", sizeof("²")-1 },
455 { "³", sizeof("³")-1 },
456 { "´", sizeof("´")-1 },
457 { "µ", sizeof("µ")-1 },
458 { "¶", sizeof("¶")-1 },
459 { "·", sizeof("·")-1 },
460 { "¸", sizeof("¸")-1 },
461 { "¹", sizeof("¹")-1 },
462 { "º", sizeof("º")-1 },
463 mike 1.1 { "»", sizeof("»")-1 },
464 { "¼", sizeof("¼")-1 },
465 { "½", sizeof("½")-1 },
466 { "¾", sizeof("¾")-1 },
467 { "¿", sizeof("¿")-1 },
468 { "À", sizeof("À")-1 },
469 { "Á", sizeof("Á")-1 },
470 { "Â", sizeof("Â")-1 },
471 { "Ã", sizeof("Ã")-1 },
472 { "Ä", sizeof("Ä")-1 },
473 { "Å", sizeof("Å")-1 },
474 { "Æ", sizeof("Æ")-1 },
475 { "Ç", sizeof("Ç")-1 },
476 { "È", sizeof("È")-1 },
477 { "É", sizeof("É")-1 },
478 { "Ê", sizeof("Ê")-1 },
479 { "Ë", sizeof("Ë")-1 },
480 { "Ì", sizeof("Ì")-1 },
481 { "Í", sizeof("Í")-1 },
482 { "Î", sizeof("Î")-1 },
483 { "Ï", sizeof("Ï")-1 },
484 mike 1.1 { "Ð", sizeof("Ð")-1 },
485 { "Ñ", sizeof("Ñ")-1 },
486 { "Ò", sizeof("Ò")-1 },
487 { "Ó", sizeof("Ó")-1 },
488 { "Ô", sizeof("Ô")-1 },
489 { "Õ", sizeof("Õ")-1 },
490 { "Ö", sizeof("Ö")-1 },
491 { "×", sizeof("×")-1 },
492 { "Ø", sizeof("Ø")-1 },
493 { "Ù", sizeof("Ù")-1 },
494 { "Ú", sizeof("Ú")-1 },
495 { "Û", sizeof("Û")-1 },
496 { "Ü", sizeof("Ü")-1 },
497 { "Ý", sizeof("Ý")-1 },
498 { "Þ", sizeof("Þ")-1 },
499 { "ß", sizeof("ß")-1 },
500 { "à", sizeof("à")-1 },
501 { "á", sizeof("á")-1 },
502 { "â", sizeof("â")-1 },
503 { "ã", sizeof("ã")-1 },
504 { "ä", sizeof("ä")-1 },
505 mike 1.1 { "å", sizeof("å")-1 },
506 { "æ", sizeof("æ")-1 },
507 { "ç", sizeof("ç")-1 },
508 { "è", sizeof("è")-1 },
509 { "é", sizeof("é")-1 },
510 { "ê", sizeof("ê")-1 },
511 { "ë", sizeof("ë")-1 },
512 { "ì", sizeof("ì")-1 },
513 { "í", sizeof("í")-1 },
514 { "î", sizeof("î")-1 },
515 { "ï", sizeof("ï")-1 },
516 { "ð", sizeof("ð")-1 },
517 { "ñ", sizeof("ñ")-1 },
518 { "ò", sizeof("ò")-1 },
519 { "ó", sizeof("ó")-1 },
520 { "ô", sizeof("ô")-1 },
521 { "õ", sizeof("õ")-1 },
522 { "ö", sizeof("ö")-1 },
523 { "÷", sizeof("÷")-1 },
524 { "ø", sizeof("ø")-1 },
525 { "ù", sizeof("ù")-1 },
526 mike 1.1 { "ú", sizeof("ú")-1 },
527 { "û", sizeof("û")-1 },
528 { "ü", sizeof("ü")-1 },
529 { "ý", sizeof("ý")-1 },
530 { "þ", sizeof("þ")-1 },
531 { "ÿ", sizeof("ÿ")-1 },
532 };
533
534
535 /* [A-Za-z_] */
536 static inline bool _IsFirst(char c)
537 {
538 if (isalpha(c) || c == '_')
539 return true;
540
541 return false;
542 //return (_nameChar[(unsigned int)c] & 2) ? true : false;
543 }
544
545 /* [A-Za-z0-9_-.:] */
546 static inline bool _IsInner(char c)
547 mike 1.1 {
548 if (isalpha(c) || isdigit(c) || c=='_' || c=='-' || c=='.' || c==':')
549 return true;
550
551 return false;
552 }
553
554 static bool _ValidIdentifier(const char* p)
555 {
556 if (!_IsFirst(*p))
557 return false;
558
559 p++;
560
561 while (*p)
562 {
563 if (!_IsInner(*p))
564 return false;
565
566 p++;
567 }
568 mike 1.1
569 return true;
570 }
571
572 static void _PutRaw(XMLWriterRep* rep, const char* str)
573 {
574 size_t len = strlen(str);
575
576 if (len)
577 Buf_App(&rep->buf, str, len);
578 }
579
580 static void _PutChars(XMLWriterRep* _rep, const char* str)
581 {
582 const unsigned char* p = reinterpret_cast<const unsigned char*>(str);
583
584 while (*p)
585 {
586 Buf_App(&_rep->buf, _encode[*p].str, _encode[*p].len);
587 p++;
588 }
589 mike 1.1 }
590
591 //
592 // Helper function to put start tag, empty tag, or processing instruction.
593 //
594 // The 'type' parameter is one of these:
595 // 's' -- start tag
596 // 'e' -- empty tag
597 // 'p' -- processing instruction.
598 //
599 bool _PutTag(
600 XMLWriterRep* _rep,
601 const char* tagName,
602 const std::vector<XMLAttr>& attrs,
603 char type)
604 {
605 if (!_ValidIdentifier(tagName))
606 return false;
607
608 if (type == 'p')
609 _PutRaw(_rep, "<?");
610 mike 1.1 else
611 _PutRaw(_rep, "<");
612
613 _PutRaw(_rep, tagName);
614
615 for (size_t i = 0; i < attrs.size(); i++)
616 {
617 const XMLAttr& a = attrs[i];
618
619 if (!_ValidIdentifier(a.name.c_str()))
620 return false;
621
622 _PutRaw(_rep, " ");
623 _PutRaw(_rep, a.name.c_str());
624 _PutRaw(_rep, "=\"");
625 _PutChars(_rep, a.value.c_str());
626 _PutRaw(_rep, "\"");
627 }
628
629 if (type == 'p')
630 _PutRaw(_rep, "?>");
631 mike 1.1 else if (type == 'e')
632 _PutRaw(_rep, "/>");
633 else
634 _PutRaw(_rep, ">");
635
636 return true;
637 }
638
639 XMLWriter::XMLWriter()
640 {
641 _rep = new XMLWriterRep();
642 }
643
644 XMLWriter::~XMLWriter()
645 {
646 delete _rep;
647 }
648
649 std::string XMLWriter::GetText() const
650 {
651 return string(
652 mike 1.1 reinterpret_cast<const char*>(_rep->buf.data), _rep->buf.size);
653 }
654
655 void XMLWriter::EnableLineSeparators()
656 {
657 _rep->enableLineSeparators = true;
658 }
659
660 void XMLWriter::DisableLineSeparators()
661 {
662 _rep->enableLineSeparators = false;
663 }
664
665 bool XMLWriter::PutStartTag(
666 const char* tagName,
667 const std::vector<XMLAttr>& attrs)
668 {
669 if (!_PutTag(_rep, tagName, attrs, 's'))
670 return false;
671
672 if (_rep->enableLineSeparators)
673 mike 1.1 PutLineSeparator();
674
675 return true;
676 }
677
678 bool XMLWriter::PutStartTag(const char* tagName)
679 {
680 vector<XMLAttr> attrs;
681
682 if (!_PutTag(_rep, tagName, attrs, 's'))
683 return false;
684
685 if (_rep->enableLineSeparators)
686 PutLineSeparator();
687
688 return true;
689 }
690
691 bool XMLWriter::PutEmptyTag(
692 const char* tagName,
693 const std::vector<XMLAttr>& attrs)
694 mike 1.1 {
695 if (!_PutTag(_rep, tagName, attrs, 'e'))
696 return false;
697
698 if (_rep->enableLineSeparators)
699 PutLineSeparator();
700
701 return true;
702 }
703
704 bool XMLWriter::PutProcessingInstruction(
705 const char* tagName,
706 const std::vector<XMLAttr>& attrs)
707 {
708 if (!_PutTag(_rep, tagName, attrs, 'p'))
709 return false;
710
711 if (_rep->enableLineSeparators)
712 PutLineSeparator();
713
714 return true;
715 mike 1.1 }
716
717 bool XMLWriter::PutEndTag(const char* tagName)
718 {
719 if (!_ValidIdentifier(tagName))
720 return false;
721
722 _PutRaw(_rep, "</");
723 _PutRaw(_rep, tagName);
724 _PutRaw(_rep, ">");
725
726 if (_rep->enableLineSeparators)
727 PutLineSeparator();
728
729 return true;
730 }
731
732 void XMLWriter::PutCharacterData(const char* str)
733 {
734 _PutChars(_rep, str);
735
736 mike 1.1 if (_rep->enableLineSeparators)
737 PutLineSeparator();
738 }
739
740 void XMLWriter::PutComment(const char* str)
741 {
742 _PutRaw(_rep, "<!--");
743 _PutChars(_rep, str);
744 _PutRaw(_rep, "-->");
745
746 if (_rep->enableLineSeparators)
747 PutLineSeparator();
748 }
749
750 void XMLWriter::PutCDATA(const char* str)
751 {
752 _PutRaw(_rep, "<![CDATA[");
753 _PutRaw(_rep, str);
754 _PutRaw(_rep, "]]>");
755
756 if (_rep->enableLineSeparators)
757 mike 1.1 PutLineSeparator();
758 }
759
760 void XMLWriter::PutLineSeparator()
761 {
762 _PutRaw(_rep, "\r\n");
763 }
764
765 XMLCXX_END
|