Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmXMLSafe.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmXMLSafe.h"
13
14 #include "cm_utf8.h"
15
16 #include <cmsys/ios/iostream>
17 #include <cmsys/ios/sstream>
18
19 #include <string.h>
20 #include <stdio.h>
21
22 //----------------------------------------------------------------------------
23 cmXMLSafe::cmXMLSafe(const char* s):
24   Data(s),
25   Size(static_cast<unsigned long>(strlen(s))),
26   DoQuotes(true)
27 {
28 }
29
30 //----------------------------------------------------------------------------
31 cmXMLSafe::cmXMLSafe(cmsys_stl::string const& s):
32     Data(s.c_str()),
33     Size(static_cast<unsigned long>(s.length())),
34     DoQuotes(true)
35 {
36 }
37
38 //----------------------------------------------------------------------------
39 cmXMLSafe& cmXMLSafe::Quotes(bool b)
40 {
41   this->DoQuotes = b;
42   return *this;
43 }
44
45 //----------------------------------------------------------------------------
46 cmsys_stl::string cmXMLSafe::str()
47 {
48   cmsys_ios::ostringstream ss;
49   ss << *this;
50   return ss.str();
51 }
52
53 //----------------------------------------------------------------------------
54 cmsys_ios::ostream& operator<<(cmsys_ios::ostream& os, cmXMLSafe const& self)
55 {
56   char const* first = self.Data;
57   char const* last = self.Data + self.Size;
58   while(first != last)
59     {
60     unsigned int ch;
61     if(const char* next = cm_utf8_decode_character(first, last, &ch))
62       {
63       // http://www.w3.org/TR/REC-xml/#NT-Char
64       if((ch >= 0x20 && ch <= 0xD7FF) ||
65          (ch >= 0xE000 && ch <= 0xFFFD) ||
66          (ch >= 0x10000 && ch <= 0x10FFFF) ||
67           ch == 0x9 || ch == 0xA || ch == 0xD)
68         {
69         switch(ch)
70           {
71           // Escape XML control characters.
72           case '&': os << "&amp;"; break;
73           case '<': os << "&lt;"; break;
74           case '>': os << "&gt;"; break;
75           case '"': os << (self.DoQuotes? "&quot;" : "\""); break;
76           case '\'': os << (self.DoQuotes? "&apos;" : "'"); break;
77           case '\r': break; // Ignore CR
78           // Print the UTF-8 character.
79           default: os.write(first, next-first); break;
80           }
81         }
82       else
83         {
84         // Use a human-readable hex value for this invalid character.
85         char buf[16];
86         sprintf(buf, "%X", ch);
87         os << "[NON-XML-CHAR-0x" << buf << "]";
88         }
89
90       first = next;
91       }
92     else
93       {
94       ch = static_cast<unsigned char>(*first++);
95       // Use a human-readable hex value for this invalid byte.
96       char buf[16];
97       sprintf(buf, "%X", ch);
98       os << "[NON-UTF-8-BYTE-0x" << buf << "]";
99       }
100     }
101   return os;
102 }