507978f5eebe1f9c6f698161db999c1c763d36a2
[tpot/pegasus/.git] / src / Pegasus / Common / XmlGenerator.cpp
1 //%LICENSE////////////////////////////////////////////////////////////////
2 //
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
8 // License.
9 //
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:
16 //
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
19 //
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.
27 //
28 //////////////////////////////////////////////////////////////////////////
29 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32 #include <cstdlib>
33 #include <cstdio>
34
35 #include <Pegasus/Common/Config.h>
36 #include "XmlGenerator.h"
37 #include "Constants.h"
38 #include "StrLit.h"
39 #include "CommonUTF.h"
40 #include "StringConversion.h"
41 #include "LanguageParser.h"
42 #include "AutoPtr.h"
43
44 PEGASUS_NAMESPACE_BEGIN
45
46 ////////////////////////////////////////////////////////////////////////////////
47 //
48 // SpecialChar and table.
49 //
50 ////////////////////////////////////////////////////////////////////////////////
51
52 // Note: we cannot use StrLit here since it has a constructor (forbids
53 // structure initialization).
54
55 struct SpecialChar
56 {
57     const char* str;
58     Uint32 size;
59 };
60
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
63 // length in bytes.
64 static const SpecialChar _specialChars[] =
65 {
66     {STRLIT_ARGS("&#0;")},
67     {STRLIT_ARGS("&#1;")},
68     {STRLIT_ARGS("&#2;")},
69     {STRLIT_ARGS("&#3;")},
70     {STRLIT_ARGS("&#4;")},
71     {STRLIT_ARGS("&#5;")},
72     {STRLIT_ARGS("&#6;")},
73     {STRLIT_ARGS("&#7;")},
74     {STRLIT_ARGS("&#8;")},
75     {STRLIT_ARGS("&#9;")},
76     {STRLIT_ARGS("&#10;")},
77     {STRLIT_ARGS("&#11;")},
78     {STRLIT_ARGS("&#12;")},
79     {STRLIT_ARGS("&#13;")},
80     {STRLIT_ARGS("&#14;")},
81     {STRLIT_ARGS("&#15;")},
82     {STRLIT_ARGS("&#16;")},
83     {STRLIT_ARGS("&#17;")},
84     {STRLIT_ARGS("&#18;")},
85     {STRLIT_ARGS("&#19;")},
86     {STRLIT_ARGS("&#20;")},
87     {STRLIT_ARGS("&#21;")},
88     {STRLIT_ARGS("&#22;")},
89     {STRLIT_ARGS("&#23;")},
90     {STRLIT_ARGS("&#24;")},
91     {STRLIT_ARGS("&#25;")},
92     {STRLIT_ARGS("&#26;")},
93     {STRLIT_ARGS("&#27;")},
94     {STRLIT_ARGS("&#28;")},
95     {STRLIT_ARGS("&#29;")},
96     {STRLIT_ARGS("&#30;")},
97     {STRLIT_ARGS("&#31;")},
98     {STRLIT_ARGS(" ")},
99     {STRLIT_ARGS("!")},
100     {STRLIT_ARGS("&quot;")},
101     {STRLIT_ARGS("#")},
102     {STRLIT_ARGS("$")},
103     {STRLIT_ARGS("%")},
104     {STRLIT_ARGS("&amp;")},
105     {STRLIT_ARGS("&apos;")},
106     {STRLIT_ARGS("(")},
107     {STRLIT_ARGS(")")},
108     {STRLIT_ARGS("*")},
109     {STRLIT_ARGS("+")},
110     {STRLIT_ARGS(",")},
111     {STRLIT_ARGS("-")},
112     {STRLIT_ARGS(".")},
113     {STRLIT_ARGS("/")},
114     {STRLIT_ARGS("0")},
115     {STRLIT_ARGS("1")},
116     {STRLIT_ARGS("2")},
117     {STRLIT_ARGS("3")},
118     {STRLIT_ARGS("4")},
119     {STRLIT_ARGS("5")},
120     {STRLIT_ARGS("6")},
121     {STRLIT_ARGS("7")},
122     {STRLIT_ARGS("8")},
123     {STRLIT_ARGS("9")},
124     {STRLIT_ARGS(":")},
125     {STRLIT_ARGS(";")},
126     {STRLIT_ARGS("&lt;")},
127     {STRLIT_ARGS("=")},
128     {STRLIT_ARGS("&gt;")},
129     {STRLIT_ARGS("?")},
130     {STRLIT_ARGS("@")},
131     {STRLIT_ARGS("A")},
132     {STRLIT_ARGS("B")},
133     {STRLIT_ARGS("C")},
134     {STRLIT_ARGS("D")},
135     {STRLIT_ARGS("E")},
136     {STRLIT_ARGS("F")},
137     {STRLIT_ARGS("G")},
138     {STRLIT_ARGS("H")},
139     {STRLIT_ARGS("I")},
140     {STRLIT_ARGS("J")},
141     {STRLIT_ARGS("K")},
142     {STRLIT_ARGS("L")},
143     {STRLIT_ARGS("M")},
144     {STRLIT_ARGS("N")},
145     {STRLIT_ARGS("O")},
146     {STRLIT_ARGS("P")},
147     {STRLIT_ARGS("Q")},
148     {STRLIT_ARGS("R")},
149     {STRLIT_ARGS("S")},
150     {STRLIT_ARGS("T")},
151     {STRLIT_ARGS("U")},
152     {STRLIT_ARGS("V")},
153     {STRLIT_ARGS("W")},
154     {STRLIT_ARGS("X")},
155     {STRLIT_ARGS("Y")},
156     {STRLIT_ARGS("Z")},
157     {STRLIT_ARGS("[")},
158     {STRLIT_ARGS("\\")},
159     {STRLIT_ARGS("]")},
160     {STRLIT_ARGS("^")},
161     {STRLIT_ARGS("_")},
162     {STRLIT_ARGS("`")},
163     {STRLIT_ARGS("a")},
164     {STRLIT_ARGS("b")},
165     {STRLIT_ARGS("c")},
166     {STRLIT_ARGS("d")},
167     {STRLIT_ARGS("e")},
168     {STRLIT_ARGS("f")},
169     {STRLIT_ARGS("g")},
170     {STRLIT_ARGS("h")},
171     {STRLIT_ARGS("i")},
172     {STRLIT_ARGS("j")},
173     {STRLIT_ARGS("k")},
174     {STRLIT_ARGS("l")},
175     {STRLIT_ARGS("m")},
176     {STRLIT_ARGS("n")},
177     {STRLIT_ARGS("o")},
178     {STRLIT_ARGS("p")},
179     {STRLIT_ARGS("q")},
180     {STRLIT_ARGS("r")},
181     {STRLIT_ARGS("s")},
182     {STRLIT_ARGS("t")},
183     {STRLIT_ARGS("u")},
184     {STRLIT_ARGS("v")},
185     {STRLIT_ARGS("w")},
186     {STRLIT_ARGS("x")},
187     {STRLIT_ARGS("y")},
188     {STRLIT_ARGS("z")},
189     {STRLIT_ARGS("{")},
190     {STRLIT_ARGS("|")},
191     {STRLIT_ARGS("}")},
192     {STRLIT_ARGS("~")},
193     {STRLIT_ARGS("&#127;")},
194 };
195
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
198 // index this array.
199 static const int _isSpecialChar7[] =
200 {
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,
205 };
206
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
209 // index this array.
210 static const int _isNormalChar7[] =
211 {
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,
216 };
217
218
219 ////////////////////////////////////////////////////////////////////////////////
220
221 Buffer& operator<<(Buffer& out, const Char16& x)
222 {
223     XmlGenerator::append(out, x);
224     return out;
225 }
226
227 Buffer& operator<<(Buffer& out, const String& x)
228 {
229     XmlGenerator::append(out, x);
230     return out;
231 }
232
233 Buffer& operator<<(Buffer& out, const Buffer& x)
234 {
235     out.append(x.getData(), x.size());
236     return out;
237 }
238
239 Buffer& operator<<(Buffer& out, Uint32 x)
240 {
241     XmlGenerator::append(out, x);
242     return out;
243 }
244
245 Buffer& operator<<(Buffer& out, const CIMName& name)
246 {
247     XmlGenerator::append(out, name.getString ());
248     return out;
249 }
250
251 Buffer& operator<<(Buffer& out, const AcceptLanguageList& al)
252 {
253     XmlGenerator::append(out, LanguageParser::buildAcceptLanguageHeader(al));
254     return out;
255 }
256
257 Buffer& operator<<(Buffer& out, const ContentLanguageList& cl)
258 {
259     XmlGenerator::append(out, LanguageParser::buildContentLanguageHeader(cl));
260     return out;
261 }
262
263 const StrLit XmlGenerator::_XmlWriterTypeStrings[17] =
264 {
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\"")
274 };
275
276 const StrLit XmlGenerator::_XmlWriterKeyTypeStrings[17] =
277 {
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
287        generated XML */
288     STRLIT("reference"), STRLIT("object"),
289     STRLIT("instance")
290 };
291
292 void XmlGenerator::_appendChar(Buffer& out, const Char16& c)
293 {
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.
299     char str[6];
300     memset(str,0x00,sizeof(str));
301     Uint8* charIN = (Uint8 *)&c;
302
303     const Uint16 *strsrc = (Uint16 *)charIN;
304     Uint16 *endsrc = (Uint16 *)&charIN[1];
305
306     Uint8 *strtgt = (Uint8 *)str;
307     Uint8 *endtgt = (Uint8 *)&str[5];
308
309     UTF16toUTF8(
310         &strsrc,
311         endsrc,
312         &strtgt,
313         endtgt);
314
315     out.append(str, UTF_8_COUNT_TRAIL_BYTES(str[0]) + 1);
316 }
317
318 void XmlGenerator::_appendSpecialChar7(Buffer& out, char c)
319 {
320     if (_isSpecialChar7[int(c)])
321         out.append(_specialChars[int(c)].str, _specialChars[int(c)].size);
322     else
323         out.append(c);
324 }
325
326 void XmlGenerator::_appendSpecialChar(Buffer& out, const Char16& c)
327 {
328     if (c < 128)
329         _appendSpecialChar7(out, char(c));
330     else
331         _appendChar(out, c);
332 }
333
334 void XmlGenerator::_appendSpecialChar(PEGASUS_STD(ostream)& os, char c)
335 {
336     if ( ((c < 0x20) && (c >= 0)) || (c == 0x7f) )
337     {
338         char scratchBuffer[22];
339         Uint32 outputLength;
340         const char * output = Uint8ToString(scratchBuffer,
341                                             static_cast<Uint8>(c),
342                                             outputLength);
343         os << "&#" << output << ";";
344     }
345     else
346     {
347         switch (c)
348         {
349             case '&':
350                 os << "&amp;";
351                 break;
352
353             case '<':
354                 os << "&lt;";
355                 break;
356
357             case '>':
358                 os << "&gt;";
359                 break;
360
361             case '"':
362                 os << "&quot;";
363                 break;
364
365             case '\'':
366                 os << "&apos;";
367                 break;
368
369             default:
370                 os << c;
371         }
372     }
373 }
374
375 void XmlGenerator::_appendSurrogatePair(Buffer& out, Uint16 high, Uint16 low)
376 {
377     char str[6];
378     Uint8 charIN[5];
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];
384
385     Uint8 *strtgt = (Uint8 *)str;
386     Uint8 *endtgt = (Uint8 *)&str[5];
387
388     UTF16toUTF8(
389         &strsrc,
390         endsrc,
391         &strtgt,
392         endtgt);
393
394     Uint32 number1 = UTF_8_COUNT_TRAIL_BYTES(str[0]) + 1;
395     out.append(str,number1);
396 }
397
398 void XmlGenerator::_appendSpecial(PEGASUS_STD(ostream)& os, const char* str)
399 {
400     while (*str)
401         _appendSpecialChar(os, *str++);
402 }
403
404 void XmlGenerator::append(Buffer& out, const Char16& x)
405 {
406     _appendChar(out, x);
407 }
408
409 void XmlGenerator::append(Buffer& out, Boolean x)
410 {
411     if (x)
412         out.append(STRLIT_ARGS("TRUE"));
413     else
414         out.append(STRLIT_ARGS("FALSE"));
415 }
416
417 void XmlGenerator::append(Buffer& out, Uint32 x)
418 {
419     Uint32 outputLength=0;
420     char buffer[22];
421     const char * output = Uint32ToString(buffer, x, outputLength);
422     out.append(output, outputLength);
423 }
424
425 void XmlGenerator::append(Buffer& out, Sint32 x)
426 {
427     Uint32 outputLength=0;
428     char buffer[22];
429     const char * output = Sint32ToString(buffer, x, outputLength);
430     out.append(output, outputLength);
431 }
432
433 void XmlGenerator::append(Buffer& out, Uint64 x)
434 {
435     Uint32 outputLength=0;
436     char buffer[22];
437     const char * output = Uint64ToString(buffer, x, outputLength);
438     out.append(output, outputLength);
439 }
440
441 void XmlGenerator::append(Buffer& out, Sint64 x)
442 {
443     Uint32 outputLength=0;
444     char buffer[22];
445     const char * output = Sint64ToString(buffer, x, outputLength);
446     out.append(output, outputLength);
447 }
448
449 void XmlGenerator::append(Buffer& out, Real32 x)
450 {
451     Uint32 outputLength=0;
452     char buffer[128];
453     const char * output = Real32ToString(buffer, x, outputLength);
454     out.append(output, outputLength);
455 }
456
457 void XmlGenerator::append(Buffer& out, Real64 x)
458 {
459     Uint32 outputLength=0;
460     char buffer[128];
461     const char * output = Real64ToString(buffer, x, outputLength);
462     out.append(output, outputLength);
463 }
464
465 void XmlGenerator::append(Buffer& out, const char* str)
466 {
467     size_t n = strlen(str);
468     out.append(str, n);
469 }
470
471 void XmlGenerator::append(Buffer& out, const String& str)
472 {
473     const Uint16* p = (const Uint16*)str.getChar16Data();
474     size_t n = str.size();
475
476     // Handle leading ASCII 7 characers in these next two loops (use unrolling).
477
478     while (n >= 8 && ((p[0]|p[1]|p[2]|p[3]|p[4]|p[5]|p[6]|p[7]) & 0xFF80) == 0)
479     {
480         out.append(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
481         p += 8;
482         n -= 8;
483     }
484
485     while (n >= 4 && ((p[0]|p[1]|p[2]|p[3]) & 0xFF80) == 0)
486     {
487         out.append(p[0], p[1], p[2], p[3]);
488         p += 4;
489         n -= 4;
490     }
491
492     while (n--)
493     {
494         Uint16 c = *p++;
495
496         // Special processing for UTF8 case:
497
498         if (c < 128)
499         {
500             out.append(c);
501             continue;
502         }
503
504         // Handle UTF8 case (if reached).
505
506         if (((c >= FIRST_HIGH_SURROGATE) && (c <= LAST_HIGH_SURROGATE)) ||
507             ((c >= FIRST_LOW_SURROGATE) && (c <= LAST_LOW_SURROGATE)))
508         {
509             Char16 highSurrogate = p[-1];
510             Char16 lowSurrogate = p[0];
511             p++;
512             n--;
513
514             _appendSurrogatePair(
515                 out, Uint16(highSurrogate),Uint16(lowSurrogate));
516         }
517         else
518         {
519             _appendChar(out, c);
520         }
521     }
522 }
523
524 void XmlGenerator::appendSpecial(Buffer& out, const Char16& x)
525 {
526     _appendSpecialChar(out, x);
527 }
528
529 void XmlGenerator::appendSpecial(Buffer& out, char x)
530 {
531     _appendSpecialChar7(out, x);
532 }
533
534 void XmlGenerator::appendSpecial(Buffer& out, const char* str)
535 {
536     while (*str)
537         _appendSpecialChar7(out, *str++);
538 }
539
540 void XmlGenerator::appendSpecial(Buffer& out, const String& str)
541 {
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;
546
547     // If the first character is a space, use a character reference to avoid
548     // space compression.
549     if (*p == ' ')
550     {
551         out.append(STRLIT_ARGS("&#32;"));
552         p++;
553     }
554
555     Uint16 c;
556     while ((c = *p++) != 0)
557     {
558         if (c < 128)
559         {
560             if (_isSpecialChar7[c])
561             {
562                 // Write the character reference for the special character
563                 out.append(
564                     _specialChars[int(c)].str, _specialChars[int(c)].size);
565                 prevCharIsSpace = false;
566             }
567             else if (prevCharIsSpace && (c == ' '))
568             {
569                 // Write the character reference for the space character, to
570                 // avoid compression
571                 out.append(STRLIT_ARGS("&#32;"));
572                 prevCharIsSpace = false;
573             }
574             else
575             {
576                 out.append(c);
577                 prevCharIsSpace = (c == ' ');
578             }
579         }
580         else
581         {
582             // Handle UTF8 case
583
584             if ((((c >= FIRST_HIGH_SURROGATE) && (c <= LAST_HIGH_SURROGATE)) ||
585                  ((c >= FIRST_LOW_SURROGATE) && (c <= LAST_LOW_SURROGATE))) &&
586                 *p)
587             {
588                 _appendSurrogatePair(out, c, *p++);
589             }
590             else
591             {
592                 _appendChar(out, c);
593             }
594
595             prevCharIsSpace = false;
596         }
597     }
598
599     // If the last character is a space, use a character reference to avoid
600     // space compression.
601     if (prevCharIsSpace)
602     {
603         out.remove(out.size() - 1);
604         out.append(STRLIT_ARGS("&#32;"));
605     }
606 }
607
608 // str has to be UTF-8 encoded
609 // that means the characters used cannot be larger than 7bit ASCII in value
610 // range
611 void XmlGenerator::appendSpecial(Buffer& out, const char* str, Uint32 size)
612 {
613     // employ loop unrolling and a less checking optimized Buffer access
614
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())
618     {
619         out.reserveCapacity(out.capacity() + newMaxSize);
620     }
621
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;
627
628     while (size >= 4 &&
629              (_isNormalChar7[p[0]] &
630               _isNormalChar7[p[1]] &
631               _isNormalChar7[p[2]] &
632               _isNormalChar7[p[3]]))
633     {
634         size -= 4;
635         p += 4;
636     }
637     out.append_unchecked(str,sizeStart-size);
638     str=(const char*)p;
639
640     while (size>=8)
641     {
642         register int c;
643         c = str[0];
644         if (_isSpecialChar7[c])
645         {
646             out.append_unchecked(
647                 _specialChars[c].str,
648                 _specialChars[c].size);
649         }
650         else
651         {
652             out.append_unchecked(c);
653         }
654         c = str[1];
655         if (_isSpecialChar7[c])
656         {
657             out.append_unchecked(
658                 _specialChars[c].str,
659                 _specialChars[c].size);
660         }
661         else
662         {
663             out.append_unchecked(c);
664         }
665         c = str[2];
666         if (_isSpecialChar7[c])
667         {
668             out.append_unchecked(
669                 _specialChars[c].str,
670                 _specialChars[c].size);
671         }
672         else
673         {
674             out.append_unchecked(c);
675         }
676         c = str[3];
677         if (_isSpecialChar7[c])
678         {
679             out.append_unchecked(
680                 _specialChars[c].str,
681                 _specialChars[c].size);
682         }
683         else
684         {
685             out.append_unchecked(c);
686         }
687         c = str[4];
688         if (_isSpecialChar7[c])
689         {
690             out.append_unchecked(
691                 _specialChars[c].str,
692                 _specialChars[c].size);
693         }
694         else
695         {
696             out.append_unchecked(c);
697         }
698         c = str[5];
699         if (_isSpecialChar7[c])
700         {
701             out.append_unchecked(
702                 _specialChars[c].str,
703                 _specialChars[c].size);
704         }
705         else
706         {
707             out.append_unchecked(c);
708         }
709         c = str[6];
710         if (_isSpecialChar7[c])
711         {
712             out.append_unchecked(
713                 _specialChars[c].str,
714                 _specialChars[c].size);
715         }
716         else
717         {
718             out.append_unchecked(c);
719         }
720         c = str[7];
721         if (_isSpecialChar7[c])
722         {
723             out.append_unchecked(
724                 _specialChars[c].str,
725                 _specialChars[c].size);
726         }
727         else
728         {
729             out.append_unchecked(c);
730         }
731         str+=8;
732         size-=8;
733     }
734
735     while (size>=4)
736     {
737         register int c;
738         c = str[0];
739         if (_isSpecialChar7[c])
740         {
741             out.append_unchecked(
742                 _specialChars[c].str,
743                 _specialChars[c].size);
744         }
745         else
746         {
747             out.append_unchecked(c);
748         }
749         c = str[1];
750         if (_isSpecialChar7[c])
751         {
752             out.append_unchecked(
753                 _specialChars[c].str,
754                 _specialChars[c].size);
755         }
756         else
757         {
758             out.append_unchecked(c);
759         }
760         c = str[2];
761         if (_isSpecialChar7[c])
762         {
763             out.append_unchecked(
764                 _specialChars[c].str,
765                 _specialChars[c].size);
766         }
767         else
768         {
769             out.append_unchecked(c);
770         }
771         c = str[3];
772         if (_isSpecialChar7[c])
773         {
774             out.append_unchecked(
775                 _specialChars[c].str,
776                 _specialChars[c].size);
777         }
778         else
779         {
780             out.append_unchecked(c);
781         }
782         str+=4;
783         size-=4;
784     }
785
786     while (size--)
787     {
788         register int c;
789         c=*str;
790         if (_isSpecialChar7[c])
791         {
792             out.append_unchecked(
793                 _specialChars[c].str,
794                 _specialChars[c].size);
795         }
796         else
797         {
798             out.append_unchecked(c);
799         }
800         str++;
801     }
802 }
803
804
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 = '{' '}' '|' '\\' '^' '[' ']' '`'
812 //
813
814 static const char _is_uri[128] =
815 {
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,
820 };
821
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)
826 {
827     Uint8 c = (Uint8)char8;
828
829 #ifndef PEGASUS_DO_NOT_IMPLEMENT_URI_ENCODING
830     if (c > 127 || _is_uri[int(c)])
831     {
832         char hexencoding[4];
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 */
839     }
840     else
841 #endif
842     {
843         outString.append((Uint16)c);
844     }
845 }
846
847 String XmlGenerator::encodeURICharacters(const Buffer& uriString)
848 {
849     String encodedString;
850
851     for (Uint32 i=0; i<uriString.size(); i++)
852     {
853         _encodeURIChar(encodedString, uriString[i]);
854     }
855
856     return encodedString;
857 }
858
859 String XmlGenerator::encodeURICharacters(const String& uriString)
860 {
861     String encodedString;
862
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
865
866     // First, convert to UTF-8 (include handling of surrogate pairs)
867     Buffer utf8;
868     for (Uint32 i = 0; i < uriString.size(); i++)
869     {
870         Uint16 c = uriString[i];
871
872         if (((c >= FIRST_HIGH_SURROGATE) && (c <= LAST_HIGH_SURROGATE)) ||
873             ((c >= FIRST_LOW_SURROGATE) && (c <= LAST_LOW_SURROGATE)))
874         {
875             Char16 highSurrogate = uriString[i];
876             Char16 lowSurrogate = uriString[++i];
877
878             _appendSurrogatePair(
879                 utf8, Uint16(highSurrogate),Uint16(lowSurrogate));
880         }
881         else
882         {
883             _appendChar(utf8, uriString[i]);
884         }
885     }
886
887     // Second, escape the non HTTP-safe chars
888     for (Uint32 i=0; i<utf8.size(); i++)
889     {
890         _encodeURIChar(encodedString, utf8[i]);
891     }
892
893     return encodedString;
894 }
895
896 //------------------------------------------------------------------------------
897 //
898 // _printAttributes()
899 //
900 //------------------------------------------------------------------------------
901
902 void XmlGenerator::_printAttributes(
903     PEGASUS_STD(ostream)& os,
904     const XmlAttribute* attributes,
905     Uint32 attributeCount)
906 {
907     for (Uint32 i = 0; i < attributeCount; i++)
908     {
909         os << attributes[i].name << "=";
910
911         os << '"';
912         _appendSpecial(os, attributes[i].value);
913         os << '"';
914
915         if (i + 1 != attributeCount)
916             os << ' ';
917     }
918 }
919
920 //------------------------------------------------------------------------------
921 //
922 // _indent()
923 //
924 //------------------------------------------------------------------------------
925
926 void XmlGenerator::_indent(
927     PEGASUS_STD(ostream)& os,
928     Uint32 level,
929     Uint32 indentChars)
930 {
931     Uint32 n = level * indentChars;
932
933     for (Uint32 i = 0; i < n; i++)
934         os << ' ';
935 }
936
937 //------------------------------------------------------------------------------
938 //
939 // indentedPrint()
940 //
941 //------------------------------------------------------------------------------
942
943 void XmlGenerator::indentedPrint(
944     PEGASUS_STD(ostream)& os,
945     const char* text,
946     Uint32 indentChars)
947 {
948     AutoArrayPtr<char> tmp(strcpy(new char[strlen(text) + 1], text));
949
950     XmlParser parser(tmp.get());
951     XmlEntry entry;
952     Stack<const char*> stack;
953
954     while (parser.next(entry))
955     {
956         switch (entry.type)
957         {
958             case XmlEntry::XML_DECLARATION:
959             {
960                 _indent(os, stack.size(), indentChars);
961
962                 os << "<?" << entry.text << " ";
963                 _printAttributes(
964                     os, entry.attributes.getData(), entry.attributes.size());
965                 os << "?>";
966                 break;
967             }
968
969             case XmlEntry::START_TAG:
970             {
971                 _indent(os, stack.size(), indentChars);
972
973                 os << "<" << entry.text;
974
975                 if (entry.attributes.size())
976                     os << ' ';
977
978                 _printAttributes(
979                     os, entry.attributes.getData(), entry.attributes.size());
980                 os << ">";
981                 stack.push(entry.text);
982                 break;
983             }
984
985             case XmlEntry::EMPTY_TAG:
986             {
987                 _indent(os, stack.size(), indentChars);
988
989                 os << "<" << entry.text << " ";
990                 _printAttributes(
991                     os, entry.attributes.getData(), entry.attributes.size());
992                 os << "/>";
993                 break;
994             }
995
996             case XmlEntry::END_TAG:
997             {
998                 if (!stack.isEmpty() && strcmp(stack.top(), entry.text) == 0)
999                     stack.pop();
1000
1001                 _indent(os, stack.size(), indentChars);
1002
1003                 os << "</" << entry.text << ">";
1004                 break;
1005             }
1006
1007             case XmlEntry::COMMENT:
1008             {
1009                 _indent(os, stack.size(), indentChars);
1010                 os << "<!--";
1011                 _appendSpecial(os, entry.text);
1012                 os << "-->";
1013                 break;
1014             }
1015
1016             case XmlEntry::CONTENT:
1017             {
1018                 _indent(os, stack.size(), indentChars);
1019                 _appendSpecial(os, entry.text);
1020                 break;
1021             }
1022
1023             case XmlEntry::CDATA:
1024             {
1025                 _indent(os, stack.size(), indentChars);
1026                 os << "<![CDATA[" << entry.text << "]]>";
1027                 break;
1028             }
1029
1030             case XmlEntry::DOCTYPE:
1031             {
1032                 _indent(os, stack.size(), indentChars);
1033                 os << "<!DOCTYPE...>";
1034                 break;
1035             }
1036         }
1037
1038         os << PEGASUS_STD(endl);
1039     }
1040 }
1041
1042 PEGASUS_NAMESPACE_END