cmXMLSafe.cxx 3.0 KB

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