Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 08:52:13

0001 
0002 //              Copyright Catch2 Authors
0003 // Distributed under the Boost Software License, Version 1.0.
0004 //   (See accompanying file LICENSE.txt or copy at
0005 //        https://www.boost.org/LICENSE_1_0.txt)
0006 
0007 // SPDX-License-Identifier: BSL-1.0
0008 #ifndef CATCH_XMLWRITER_HPP_INCLUDED
0009 #define CATCH_XMLWRITER_HPP_INCLUDED
0010 
0011 #include <catch2/internal/catch_reusable_string_stream.hpp>
0012 #include <catch2/internal/catch_stringref.hpp>
0013 
0014 #include <iosfwd>
0015 #include <vector>
0016 #include <cstdint>
0017 
0018 namespace Catch {
0019     enum class XmlFormatting : std::uint8_t {
0020         None = 0x00,
0021         Indent = 0x01,
0022         Newline = 0x02,
0023     };
0024 
0025     constexpr XmlFormatting operator|( XmlFormatting lhs, XmlFormatting rhs ) {
0026         return static_cast<XmlFormatting>( static_cast<std::uint8_t>( lhs ) |
0027                                            static_cast<std::uint8_t>( rhs ) );
0028     }
0029 
0030     constexpr XmlFormatting operator&( XmlFormatting lhs, XmlFormatting rhs ) {
0031         return static_cast<XmlFormatting>( static_cast<std::uint8_t>( lhs ) &
0032                                            static_cast<std::uint8_t>( rhs ) );
0033     }
0034 
0035 
0036     /**
0037      * Helper for XML-encoding text (escaping angle brackets, quotes, etc)
0038      *
0039      * Note: doesn't take ownership of passed strings, and thus the
0040      *       encoded string must outlive the encoding instance.
0041      */
0042     class XmlEncode {
0043     public:
0044         enum ForWhat { ForTextNodes, ForAttributes };
0045 
0046         constexpr XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes ):
0047             m_str( str ), m_forWhat( forWhat ) {}
0048 
0049 
0050         void encodeTo( std::ostream& os ) const;
0051 
0052         friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
0053 
0054     private:
0055         StringRef m_str;
0056         ForWhat m_forWhat;
0057     };
0058 
0059     class XmlWriter {
0060     public:
0061 
0062         class ScopedElement {
0063         public:
0064             ScopedElement( XmlWriter* writer, XmlFormatting fmt );
0065 
0066             ScopedElement( ScopedElement&& other ) noexcept;
0067             ScopedElement& operator=( ScopedElement&& other ) noexcept;
0068 
0069             ~ScopedElement();
0070 
0071             ScopedElement&
0072             writeText( StringRef text,
0073                        XmlFormatting fmt = XmlFormatting::Newline |
0074                                            XmlFormatting::Indent );
0075 
0076             ScopedElement& writeAttribute( StringRef name,
0077                                            StringRef attribute );
0078             template <typename T,
0079                       // Without this SFINAE, this overload is a better match
0080                       // for `std::string`, `char const*`, `char const[N]` args.
0081                       // While it would still work, it would cause code bloat
0082                       // and multiple iteration over the strings
0083                       typename = typename std::enable_if_t<
0084                           !std::is_convertible<T, StringRef>::value>>
0085             ScopedElement& writeAttribute( StringRef name,
0086                                            T const& attribute ) {
0087                 m_writer->writeAttribute( name, attribute );
0088                 return *this;
0089             }
0090 
0091         private:
0092             XmlWriter* m_writer = nullptr;
0093             XmlFormatting m_fmt;
0094         };
0095 
0096         XmlWriter( std::ostream& os );
0097         ~XmlWriter();
0098 
0099         XmlWriter( XmlWriter const& ) = delete;
0100         XmlWriter& operator=( XmlWriter const& ) = delete;
0101 
0102         XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
0103 
0104         ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
0105 
0106         XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
0107 
0108         //! The attribute content is XML-encoded
0109         XmlWriter& writeAttribute( StringRef name, StringRef attribute );
0110 
0111         //! Writes the attribute as "true/false"
0112         XmlWriter& writeAttribute( StringRef name, bool attribute );
0113 
0114         //! The attribute content is XML-encoded
0115         XmlWriter& writeAttribute( StringRef name, char const* attribute );
0116 
0117         //! The attribute value must provide op<<(ostream&, T). The resulting
0118         //! serialization is XML-encoded
0119         template <typename T,
0120                   // Without this SFINAE, this overload is a better match
0121                   // for `std::string`, `char const*`, `char const[N]` args.
0122                   // While it would still work, it would cause code bloat
0123                   // and multiple iteration over the strings
0124                   typename = typename std::enable_if_t<
0125                       !std::is_convertible<T, StringRef>::value>>
0126         XmlWriter& writeAttribute( StringRef name, T const& attribute ) {
0127             ReusableStringStream rss;
0128             rss << attribute;
0129             return writeAttribute( name, rss.str() );
0130         }
0131 
0132         //! Writes escaped `text` in a element
0133         XmlWriter& writeText( StringRef text,
0134                               XmlFormatting fmt = XmlFormatting::Newline |
0135                                                   XmlFormatting::Indent );
0136 
0137         //! Writes XML comment as "<!-- text -->"
0138         XmlWriter& writeComment( StringRef text,
0139                                  XmlFormatting fmt = XmlFormatting::Newline |
0140                                                      XmlFormatting::Indent );
0141 
0142         void writeStylesheetRef( StringRef url );
0143 
0144         void ensureTagClosed();
0145 
0146     private:
0147 
0148         void applyFormatting(XmlFormatting fmt);
0149 
0150         void writeDeclaration();
0151 
0152         void newlineIfNecessary();
0153 
0154         bool m_tagIsOpen = false;
0155         bool m_needsNewline = false;
0156         std::vector<std::string> m_tags;
0157         std::string m_indent;
0158         std::ostream& m_os;
0159     };
0160 
0161 }
0162 
0163 #endif // CATCH_XMLWRITER_HPP_INCLUDED