1 //%LICENSE////////////////////////////////////////////////////////////////
3 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //////////////////////////////////////////////////////////////////////////
30 //%/////////////////////////////////////////////////////////////////////////////
35 #include <Pegasus/Common/Config.h>
36 #include "XmlGenerator.h"
37 #include "Constants.h"
39 #include "CommonUTF.h"
40 #include "StringConversion.h"
41 #include "LanguageParser.h"
44 PEGASUS_NAMESPACE_BEGIN
46 ////////////////////////////////////////////////////////////////////////////////
48 // SpecialChar and table.
50 ////////////////////////////////////////////////////////////////////////////////
52 // Note: we cannot use StrLit here since it has a constructor (forbids
53 // structure initialization).
61 // Defines encodings of special characters. Just use a 7-bit ASCII character
62 // as an index into this array to retrieve its string encoding and encoding
64 static const SpecialChar _specialChars[] =
66 {STRLIT_ARGS("�")},
67 {STRLIT_ARGS("")},
68 {STRLIT_ARGS("")},
69 {STRLIT_ARGS("")},
70 {STRLIT_ARGS("")},
71 {STRLIT_ARGS("")},
72 {STRLIT_ARGS("")},
73 {STRLIT_ARGS("")},
74 {STRLIT_ARGS("")},
75 {STRLIT_ARGS("	")},
76 {STRLIT_ARGS(" ")},
77 {STRLIT_ARGS("")},
78 {STRLIT_ARGS("")},
79 {STRLIT_ARGS(" ")},
80 {STRLIT_ARGS("")},
81 {STRLIT_ARGS("")},
82 {STRLIT_ARGS("")},
83 {STRLIT_ARGS("")},
84 {STRLIT_ARGS("")},
85 {STRLIT_ARGS("")},
86 {STRLIT_ARGS("")},
87 {STRLIT_ARGS("")},
88 {STRLIT_ARGS("")},
89 {STRLIT_ARGS("")},
90 {STRLIT_ARGS("")},
91 {STRLIT_ARGS("")},
92 {STRLIT_ARGS("")},
93 {STRLIT_ARGS("")},
94 {STRLIT_ARGS("")},
95 {STRLIT_ARGS("")},
96 {STRLIT_ARGS("")},
97 {STRLIT_ARGS("")},
100 {STRLIT_ARGS(""")},
104 {STRLIT_ARGS("&")},
105 {STRLIT_ARGS("'")},
126 {STRLIT_ARGS("<")},
128 {STRLIT_ARGS(">")},
193 {STRLIT_ARGS("")},
196 // If _isSpecialChar7[ch] is true, then ch is a special character, which must
197 // have a special encoding in XML. But only use 7-bit ASCII characters to
199 static const int _isSpecialChar7[] =
201 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,
202 0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,
203 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
204 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
207 // If _isSpecialChar7[ch] is true, then ch is a special character, which must
208 // have a special encoding in XML. But only use 7-biat ASCII characters to
210 static const int _isNormalChar7[] =
212 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,
213 1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,
214 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
215 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
219 ////////////////////////////////////////////////////////////////////////////////
221 Buffer& operator<<(Buffer& out, const Char16& x)
223 XmlGenerator::append(out, x);
227 Buffer& operator<<(Buffer& out, const String& x)
229 XmlGenerator::append(out, x);
233 Buffer& operator<<(Buffer& out, const Buffer& x)
235 out.append(x.getData(), x.size());
239 Buffer& operator<<(Buffer& out, Uint32 x)
241 XmlGenerator::append(out, x);
245 Buffer& operator<<(Buffer& out, const CIMName& name)
247 XmlGenerator::append(out, name.getString ());
251 Buffer& operator<<(Buffer& out, const AcceptLanguageList& al)
253 XmlGenerator::append(out, LanguageParser::buildAcceptLanguageHeader(al));
257 Buffer& operator<<(Buffer& out, const ContentLanguageList& cl)
259 XmlGenerator::append(out, LanguageParser::buildContentLanguageHeader(cl));
263 const StrLit XmlGenerator::_XmlWriterTypeStrings[17] =
265 STRLIT("TYPE=\"boolean\""), STRLIT("TYPE=\"uint8\""),
266 STRLIT("TYPE=\"sint8\""), STRLIT("TYPE=\"uint16\""),
267 STRLIT("TYPE=\"sint16\""), STRLIT("TYPE=\"uint32\""),
268 STRLIT("TYPE=\"sint32\""), STRLIT("TYPE=\"uint64\""),
269 STRLIT("TYPE=\"sint64\""), STRLIT("TYPE=\"real32\""),
270 STRLIT("TYPE=\"real64\""), STRLIT("TYPE=\"char16\""),
271 STRLIT("TYPE=\"string\""), STRLIT("TYPE=\"datetime\""),
272 STRLIT("TYPE=\"reference\""), STRLIT("TYPE=\"object\""),
273 STRLIT("TYPE=\"instance\"")
276 const StrLit XmlGenerator::_XmlWriterKeyTypeStrings[17] =
278 STRLIT("boolean"), STRLIT("numeric"),
279 STRLIT("numeric"), STRLIT("numeric"),
280 STRLIT("numeric"), STRLIT("numeric"),
281 STRLIT("numeric"), STRLIT("numeric"),
282 STRLIT("numeric"), STRLIT("numeric"),
283 STRLIT("numeric"), STRLIT("string"),
284 STRLIT("string"), STRLIT("string"),
285 /* The following are not valid values for a keytype, but left in here
286 so in case something is going wrong it can be easily concluded from the
288 STRLIT("reference"), STRLIT("object"),
292 void XmlGenerator::_appendChar(Buffer& out, const Char16& c)
294 // We need to convert the Char16 to UTF8 then append the UTF8
295 // character into the array.
296 // NOTE: The UTF8 character could be several bytes long.
297 // WARNING: This function will put in replacement character for
298 // all characters that have surogate pairs.
300 memset(str,0x00,sizeof(str));
301 Uint8* charIN = (Uint8 *)&c;
303 const Uint16 *strsrc = (Uint16 *)charIN;
304 Uint16 *endsrc = (Uint16 *)&charIN[1];
306 Uint8 *strtgt = (Uint8 *)str;
307 Uint8 *endtgt = (Uint8 *)&str[5];
315 out.append(str, UTF_8_COUNT_TRAIL_BYTES(str[0]) + 1);
318 void XmlGenerator::_appendSpecialChar7(Buffer& out, char c)
320 if (_isSpecialChar7[int(c)])
321 out.append(_specialChars[int(c)].str, _specialChars[int(c)].size);
326 void XmlGenerator::_appendSpecialChar(Buffer& out, const Char16& c)
329 _appendSpecialChar7(out, char(c));
334 void XmlGenerator::_appendSpecialChar(PEGASUS_STD(ostream)& os, char c)
336 if ( ((c < 0x20) && (c >= 0)) || (c == 0x7f) )
338 char scratchBuffer[22];
340 const char * output = Uint8ToString(scratchBuffer,
341 static_cast<Uint8>(c),
343 os << "&#" << output << ";";
375 void XmlGenerator::_appendSurrogatePair(Buffer& out, Uint16 high, Uint16 low)
379 memset(str,0x00,sizeof(str));
380 memcpy(&charIN,&high,2);
381 memcpy(&charIN[2],&low,2);
382 const Uint16 *strsrc = (Uint16 *)charIN;
383 Uint16 *endsrc = (Uint16 *)&charIN[3];
385 Uint8 *strtgt = (Uint8 *)str;
386 Uint8 *endtgt = (Uint8 *)&str[5];
394 Uint32 number1 = UTF_8_COUNT_TRAIL_BYTES(str[0]) + 1;
395 out.append(str,number1);
398 void XmlGenerator::_appendSpecial(PEGASUS_STD(ostream)& os, const char* str)
401 _appendSpecialChar(os, *str++);
404 void XmlGenerator::append(Buffer& out, const Char16& x)
409 void XmlGenerator::append(Buffer& out, Boolean x)
412 out.append(STRLIT_ARGS("TRUE"));
414 out.append(STRLIT_ARGS("FALSE"));
417 void XmlGenerator::append(Buffer& out, Uint32 x)
419 Uint32 outputLength=0;
421 const char * output = Uint32ToString(buffer, x, outputLength);
422 out.append(output, outputLength);
425 void XmlGenerator::append(Buffer& out, Sint32 x)
427 Uint32 outputLength=0;
429 const char * output = Sint32ToString(buffer, x, outputLength);
430 out.append(output, outputLength);
433 void XmlGenerator::append(Buffer& out, Uint64 x)
435 Uint32 outputLength=0;
437 const char * output = Uint64ToString(buffer, x, outputLength);
438 out.append(output, outputLength);
441 void XmlGenerator::append(Buffer& out, Sint64 x)
443 Uint32 outputLength=0;
445 const char * output = Sint64ToString(buffer, x, outputLength);
446 out.append(output, outputLength);
449 void XmlGenerator::append(Buffer& out, Real32 x)
451 Uint32 outputLength=0;
453 const char * output = Real32ToString(buffer, x, outputLength);
454 out.append(output, outputLength);
457 void XmlGenerator::append(Buffer& out, Real64 x)
459 Uint32 outputLength=0;
461 const char * output = Real64ToString(buffer, x, outputLength);
462 out.append(output, outputLength);
465 void XmlGenerator::append(Buffer& out, const char* str)
467 size_t n = strlen(str);
471 void XmlGenerator::append(Buffer& out, const String& str)
473 const Uint16* p = (const Uint16*)str.getChar16Data();
474 size_t n = str.size();
476 // Handle leading ASCII 7 characers in these next two loops (use unrolling).
478 while (n >= 8 && ((p[0]|p[1]|p[2]|p[3]|p[4]|p[5]|p[6]|p[7]) & 0xFF80) == 0)
480 out.append(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
485 while (n >= 4 && ((p[0]|p[1]|p[2]|p[3]) & 0xFF80) == 0)
487 out.append(p[0], p[1], p[2], p[3]);
496 // Special processing for UTF8 case:
504 // Handle UTF8 case (if reached).
506 if (((c >= FIRST_HIGH_SURROGATE) && (c <= LAST_HIGH_SURROGATE)) ||
507 ((c >= FIRST_LOW_SURROGATE) && (c <= LAST_LOW_SURROGATE)))
509 Char16 highSurrogate = p[-1];
510 Char16 lowSurrogate = p[0];
514 _appendSurrogatePair(
515 out, Uint16(highSurrogate),Uint16(lowSurrogate));
524 void XmlGenerator::appendSpecial(Buffer& out, const Char16& x)
526 _appendSpecialChar(out, x);
529 void XmlGenerator::appendSpecial(Buffer& out, char x)
531 _appendSpecialChar7(out, x);
534 void XmlGenerator::appendSpecial(Buffer& out, const char* str)
537 _appendSpecialChar7(out, *str++);
540 void XmlGenerator::appendSpecial(Buffer& out, const String& str)
542 const Uint16* p = (const Uint16*)str.getChar16Data();
543 // prevCharIsSpace is true when the last character written to the Buffer
544 // is a space character (not a character reference).
545 Boolean prevCharIsSpace = false;
547 // If the first character is a space, use a character reference to avoid
548 // space compression.
551 out.append(STRLIT_ARGS(" "));
556 while ((c = *p++) != 0)
560 if (_isSpecialChar7[c])
562 // Write the character reference for the special character
564 _specialChars[int(c)].str, _specialChars[int(c)].size);
565 prevCharIsSpace = false;
567 else if (prevCharIsSpace && (c == ' '))
569 // Write the character reference for the space character, to
571 out.append(STRLIT_ARGS(" "));
572 prevCharIsSpace = false;
577 prevCharIsSpace = (c == ' ');
584 if ((((c >= FIRST_HIGH_SURROGATE) && (c <= LAST_HIGH_SURROGATE)) ||
585 ((c >= FIRST_LOW_SURROGATE) && (c <= LAST_LOW_SURROGATE))) &&
588 _appendSurrogatePair(out, c, *p++);
595 prevCharIsSpace = false;
599 // If the last character is a space, use a character reference to avoid
600 // space compression.
603 out.remove(out.size() - 1);
604 out.append(STRLIT_ARGS(" "));
608 // str has to be UTF-8 encoded
609 // that means the characters used cannot be larger than 7bit ASCII in value
611 void XmlGenerator::appendSpecial(Buffer& out, const char* str, Uint32 size)
613 // employ loop unrolling and a less checking optimized Buffer access
615 // Buffer cannot grow more than 6*size characters (ie. 4*size+2*size)
616 Uint32 newMaxSize = (size << 2) + (size << 1);
617 if (out.size() + newMaxSize >= out.capacity())
619 out.reserveCapacity(out.capacity() + newMaxSize);
622 // Before using a loop unrolled algorithm to pick out the special chars
623 // we are going to assume there is no special char as this is the case most
624 // of the time anyway
625 Uint32 sizeStart=size;
626 const Uint8* p= (const Uint8*) str;
629 (_isNormalChar7[p[0]] &
630 _isNormalChar7[p[1]] &
631 _isNormalChar7[p[2]] &
632 _isNormalChar7[p[3]]))
637 out.append_unchecked(str,sizeStart-size);
644 if (_isSpecialChar7[c])
646 out.append_unchecked(
647 _specialChars[c].str,
648 _specialChars[c].size);
652 out.append_unchecked(c);
655 if (_isSpecialChar7[c])
657 out.append_unchecked(
658 _specialChars[c].str,
659 _specialChars[c].size);
663 out.append_unchecked(c);
666 if (_isSpecialChar7[c])
668 out.append_unchecked(
669 _specialChars[c].str,
670 _specialChars[c].size);
674 out.append_unchecked(c);
677 if (_isSpecialChar7[c])
679 out.append_unchecked(
680 _specialChars[c].str,
681 _specialChars[c].size);
685 out.append_unchecked(c);
688 if (_isSpecialChar7[c])
690 out.append_unchecked(
691 _specialChars[c].str,
692 _specialChars[c].size);
696 out.append_unchecked(c);
699 if (_isSpecialChar7[c])
701 out.append_unchecked(
702 _specialChars[c].str,
703 _specialChars[c].size);
707 out.append_unchecked(c);
710 if (_isSpecialChar7[c])
712 out.append_unchecked(
713 _specialChars[c].str,
714 _specialChars[c].size);
718 out.append_unchecked(c);
721 if (_isSpecialChar7[c])
723 out.append_unchecked(
724 _specialChars[c].str,
725 _specialChars[c].size);
729 out.append_unchecked(c);
739 if (_isSpecialChar7[c])
741 out.append_unchecked(
742 _specialChars[c].str,
743 _specialChars[c].size);
747 out.append_unchecked(c);
750 if (_isSpecialChar7[c])
752 out.append_unchecked(
753 _specialChars[c].str,
754 _specialChars[c].size);
758 out.append_unchecked(c);
761 if (_isSpecialChar7[c])
763 out.append_unchecked(
764 _specialChars[c].str,
765 _specialChars[c].size);
769 out.append_unchecked(c);
772 if (_isSpecialChar7[c])
774 out.append_unchecked(
775 _specialChars[c].str,
776 _specialChars[c].size);
780 out.append_unchecked(c);
790 if (_isSpecialChar7[c])
792 out.append_unchecked(
793 _specialChars[c].str,
794 _specialChars[c].size);
798 out.append_unchecked(c);
805 // See http://www.ietf.org/rfc/rfc2396.txt section 2
806 // Reserved characters = ';' '/' '?' ':' '@' '&' '=' '+' '$' ','
807 // Excluded characters:
808 // Control characters = 0x00-0x1f, 0x7f
809 // Space character = 0x20
810 // Delimiters = '<' '>' '#' '%' '"'
811 // Unwise = '{' '}' '|' '\\' '^' '[' ']' '`'
814 static const char _is_uri[128] =
816 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,
817 1,1,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
818 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
819 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,
822 // Perform the necessary URI encoding of characters in HTTP header values.
823 // This is required by the HTTP/1.1 specification and the CIM/HTTP
824 // Specification (section 3.3.2).
825 void XmlGenerator::_encodeURIChar(String& outString, Sint8 char8)
827 Uint8 c = (Uint8)char8;
829 #ifndef PEGASUS_DO_NOT_IMPLEMENT_URI_ENCODING
830 if (c > 127 || _is_uri[int(c)])
833 int n = sprintf(hexencoding, "%%%X%X", c/16, c%16);
834 #ifdef PEGASUS_USE_STRING_EXTENSIONS
835 outString.append(hexencoding, n);
836 #else /* PEGASUS_USE_STRING_EXTENSIONS */
837 outString.append(hexencoding);
838 #endif /* PEGASUS_USE_STRING_EXTENSIONS */
843 outString.append((Uint16)c);
847 String XmlGenerator::encodeURICharacters(const Buffer& uriString)
849 String encodedString;
851 for (Uint32 i=0; i<uriString.size(); i++)
853 _encodeURIChar(encodedString, uriString[i]);
856 return encodedString;
859 String XmlGenerator::encodeURICharacters(const String& uriString)
861 String encodedString;
863 // See the "CIM Operations over HTTP" spec, section 3.3.2 and
864 // 3.3.3, for the treatment of non US-ASCII (UTF-8) chars
866 // First, convert to UTF-8 (include handling of surrogate pairs)
868 for (Uint32 i = 0; i < uriString.size(); i++)
870 Uint16 c = uriString[i];
872 if (((c >= FIRST_HIGH_SURROGATE) && (c <= LAST_HIGH_SURROGATE)) ||
873 ((c >= FIRST_LOW_SURROGATE) && (c <= LAST_LOW_SURROGATE)))
875 Char16 highSurrogate = uriString[i];
876 Char16 lowSurrogate = uriString[++i];
878 _appendSurrogatePair(
879 utf8, Uint16(highSurrogate),Uint16(lowSurrogate));
883 _appendChar(utf8, uriString[i]);
887 // Second, escape the non HTTP-safe chars
888 for (Uint32 i=0; i<utf8.size(); i++)
890 _encodeURIChar(encodedString, utf8[i]);
893 return encodedString;
896 //------------------------------------------------------------------------------
898 // _printAttributes()
900 //------------------------------------------------------------------------------
902 void XmlGenerator::_printAttributes(
903 PEGASUS_STD(ostream)& os,
904 const XmlAttribute* attributes,
905 Uint32 attributeCount)
907 for (Uint32 i = 0; i < attributeCount; i++)
909 os << attributes[i].name << "=";
912 _appendSpecial(os, attributes[i].value);
915 if (i + 1 != attributeCount)
920 //------------------------------------------------------------------------------
924 //------------------------------------------------------------------------------
926 void XmlGenerator::_indent(
927 PEGASUS_STD(ostream)& os,
931 Uint32 n = level * indentChars;
933 for (Uint32 i = 0; i < n; i++)
937 //------------------------------------------------------------------------------
941 //------------------------------------------------------------------------------
943 void XmlGenerator::indentedPrint(
944 PEGASUS_STD(ostream)& os,
948 AutoArrayPtr<char> tmp(strcpy(new char[strlen(text) + 1], text));
950 XmlParser parser(tmp.get());
952 Stack<const char*> stack;
954 while (parser.next(entry))
958 case XmlEntry::XML_DECLARATION:
960 _indent(os, stack.size(), indentChars);
962 os << "<?" << entry.text << " ";
964 os, entry.attributes.getData(), entry.attributes.size());
969 case XmlEntry::START_TAG:
971 _indent(os, stack.size(), indentChars);
973 os << "<" << entry.text;
975 if (entry.attributes.size())
979 os, entry.attributes.getData(), entry.attributes.size());
981 stack.push(entry.text);
985 case XmlEntry::EMPTY_TAG:
987 _indent(os, stack.size(), indentChars);
989 os << "<" << entry.text << " ";
991 os, entry.attributes.getData(), entry.attributes.size());
996 case XmlEntry::END_TAG:
998 if (!stack.isEmpty() && strcmp(stack.top(), entry.text) == 0)
1001 _indent(os, stack.size(), indentChars);
1003 os << "</" << entry.text << ">";
1007 case XmlEntry::COMMENT:
1009 _indent(os, stack.size(), indentChars);
1011 _appendSpecial(os, entry.text);
1016 case XmlEntry::CONTENT:
1018 _indent(os, stack.size(), indentChars);
1019 _appendSpecial(os, entry.text);
1023 case XmlEntry::CDATA:
1025 _indent(os, stack.size(), indentChars);
1026 os << "<![CDATA[" << entry.text << "]]>";
1030 case XmlEntry::DOCTYPE:
1032 _indent(os, stack.size(), indentChars);
1033 os << "<!DOCTYPE...>";
1038 os << PEGASUS_STD(endl);
1042 PEGASUS_NAMESPACE_END