]> git.lyx.org Git - lyx.git/blobdiff - src/xml.h
Avoid null pointer dereference
[lyx.git] / src / xml.h
index b585a48a9dc8fd90e75d87c4e96544d85c12fc42..bf72fac9463d4a5d5d2dea055bfab9c5befe17e2 100644 (file)
--- a/src/xml.h
+++ b/src/xml.h
@@ -25,7 +25,7 @@ class Paragraph;
 class OutputParams;
 
 // Inspiration for the *Tag structs and for XMLStream
-// came from MathStream and its cousins.
+// came from MathMLStream and its cousins.
 
 namespace xml {
 struct StartTag;
@@ -39,7 +39,7 @@ struct CR;
 class XMLStream {
 public:
        ///
-       explicit XMLStream(odocstream & os): os_(os), escape_(ESCAPE_ALL) {}
+       explicit XMLStream(odocstream & os): os_(os), escape_(ESCAPE_ALL), is_last_tag_cr_(true) {}
        ///
        odocstream & os() { return os_; }
        ///
@@ -82,7 +82,7 @@ public:
        enum EscapeSettings {
                ESCAPE_NONE,
                ESCAPE_AND, // meaning &
-               ESCAPE_ALL, // meaning <, >, &, at present
+               ESCAPE_ALL, // meaning <, >, &, at present, except things that are forbidden in comments
                ESCAPE_COMMENTS // Anything that is forbidden within comments
        };
        /// Sets what we are going to escape on the NEXT write.
@@ -98,13 +98,21 @@ public:
        bool isTagOpen(xml::EndTag const &, int maxdepth = -1) const;
        ///
        bool isTagPending(xml::StartTag const &, int maxdepth = -1) const;
-private:
+       /// Is the last tag that was added to the stream a new line (CR)? This is mostly to known
+       /// whether a new line must be added. Therefore, consider that an empty stream just had a CR,
+       /// that simplifies the logic using this code.
+       bool isLastTagCR() const { return is_last_tag_cr_; }
        ///
-       void clearTagDeque();
+       void writeError(std::string const &);
        ///
-       void writeError(std::string const &) const;
+       void writeError(docstring const &);
+       ///
+       typedef std::shared_ptr<xml::StartTag> TagPtr;
+       /// Returns the last element on the tag stack. XMLStream keeps ownership of the item.
+       TagPtr getLastStackTag();
+private:
        ///
-       void writeError(docstring const &) const;
+       void clearTagDeque();
        ///
        odocstream & os_;
        ///
@@ -117,7 +125,6 @@ private:
        // own these pointers and how they will be deleted, so we use shared
        // pointers.
        ///
-       typedef std::shared_ptr<xml::StartTag> TagPtr;
        typedef std::deque<TagPtr> TagDeque;
        ///
        template <typename T>
@@ -126,8 +133,8 @@ private:
        TagDeque pending_tags_;
        ///
        TagDeque tag_stack_;
-public:
-       bool pending_tags_empty() { return pending_tags_.empty();};
+       ///
+       bool is_last_tag_cr_;
 };
 
 namespace xml {
@@ -136,6 +143,7 @@ namespace xml {
 docstring escapeChar(char_type c, XMLStream::EscapeSettings e);
 
 /// Escape the given character, if necessary, to an entity.
+/// \param c must be ASCII
 docstring escapeChar(char c, XMLStream::EscapeSettings e);
 
 /// Escape a word instead of a single character
@@ -144,15 +152,18 @@ docstring escapeString(docstring const & raw, XMLStream::EscapeSettings e=XMLStr
 /// cleans \param str for use as an attribute by replacing all non-altnum by "_"
 docstring cleanAttr(docstring const & str);
 
-/// \p c must be ASCII
-docstring escapeChar(char c, XMLStream::EscapeSettings e);
-
 /// replaces illegal characters from ID attributes
 docstring cleanID(docstring const &orig);
 
 /// returns a unique numeric ID
 docstring uniqueID(docstring const & label);
 
+/// determines whether a string only contains space characters
+bool isNotOnlySpace(docstring const & str);
+
+/// trims the string to the left, i.e. remove any space-like character at the beginning of the string
+docstring trimLeft(docstring const & str);
+
 struct FontTag;
 struct EndFontTag;
 
@@ -161,23 +172,23 @@ struct EndFontTag;
 struct StartTag
 {
        ///
-       explicit StartTag(std::string const & tag) : tag_(from_ascii(tag)), keepempty_(false) {}
+       explicit StartTag(std::string const & tag) : tag_(from_ascii(tag)), keepempty_(false), tagtype_("none") {}
        ///
-       explicit StartTag(docstring const & tag) : tag_(tag), keepempty_(false) {}
+       explicit StartTag(docstring const & tag) : tag_(tag), keepempty_(false), tagtype_("none") {}
        ///
        explicit StartTag(docstring const & tag, docstring const & attr,
-                                         bool keepempty = false)
-                       : tag_(tag), attr_(attr), keepempty_(keepempty) {}
+                                         bool keepempty = false, std::string const & tagtype = "none")
+                       : tag_(tag), attr_(attr), keepempty_(keepempty), tagtype_(tagtype) {}
        ///
        explicit StartTag(std::string const & tag, std::string const & attr,
-                                         bool keepempty = false)
-                       : tag_(from_ascii(tag)), attr_(from_ascii(attr)), keepempty_(keepempty) {}
+                                         bool keepempty = false, std::string const & tagtype = "none")
+                       : tag_(from_ascii(tag)), attr_(from_utf8(attr)), keepempty_(keepempty), tagtype_(tagtype) {}
        ///
        explicit StartTag(std::string const & tag, docstring const & attr,
-                                         bool keepempty = false)
-                       : tag_(from_ascii(tag)), attr_(attr), keepempty_(keepempty) {}
+                                         bool keepempty = false, std::string const & tagtype = "none")
+                       : tag_(from_ascii(tag)), attr_(attr), keepempty_(keepempty), tagtype_(tagtype) {}
        ///
-       virtual ~StartTag() {}
+       virtual ~StartTag() = default;
        /// <tag_ attr_>
        virtual docstring writeTag() const;
        /// </tag_>
@@ -199,6 +210,8 @@ struct StartTag
        /// whether to keep things like "<tag></tag>" or discard them
        /// you would want this for td, e.g, but maybe not for a div
        bool keepempty_;
+       /// Type of tag for new-line behaviour. Either "paragraph", "inline", "block", or "none" (default).
+       std::string tagtype_;
 };
 
 
@@ -206,11 +219,13 @@ struct StartTag
 struct EndTag
 {
        ///
-       explicit EndTag(std::string tag) : tag_(from_ascii(tag)) {}
+       explicit EndTag(std::string const & tag, std::string const & tagtype = "none")
+               : tag_(from_ascii(tag)), tagtype_(tagtype) {}
        ///
-       explicit EndTag(docstring tag) : tag_(tag) {}
+       explicit EndTag(docstring const & tag, std::string const & tagtype = "none")
+               : tag_(tag), tagtype_(tagtype) {}
        ///
-       virtual ~EndTag() {}
+       virtual ~EndTag() = default;
        /// </tag_>
        virtual docstring writeEndTag() const;
        ///
@@ -220,9 +235,12 @@ struct EndTag
        bool operator!=(StartTag const & rhs) const
        { return !(*this == rhs); }
        ///
-       virtual EndFontTag const * asFontTag() const { return 0; }
+       virtual EndFontTag const * asFontTag() const { return nullptr; }
        ///
        docstring tag_;
+       /// Type of tag for new-line behaviour. Either "paragraph", "inline", "block", or "none" (default).
+       /// The value should match that of the corresponding xml::StartTag.
+       std::string tagtype_;
 };
 
 
@@ -233,27 +251,40 @@ struct CompTag
 {
        ///
        explicit CompTag(std::string const & tag)
-                       : tag_(tag) {}
+                       : tag_(from_utf8(tag)), tagtype_("none") {}
+       ///
+       explicit CompTag(docstring const & tag)
+                       : tag_(tag), tagtype_("none") {}
+       ///
+       explicit CompTag(std::string const & tag, std::string const & attr, std::string const & tagtype = "none")
+                       : tag_(from_utf8(tag)), attr_(from_utf8(attr)), tagtype_(tagtype) {}
+       ///
+       explicit CompTag(std::string const & tag, docstring const & attr, std::string const & tagtype = "none")
+                       : tag_(from_utf8(tag)), attr_(attr), tagtype_(tagtype) {}
        ///
-       explicit CompTag(std::string const & tag, std::string const & attr)
-                       : tag_(tag), attr_(attr) {}
+       explicit CompTag(docstring const & tag, std::string const & attr, std::string const & tagtype = "none")
+                       : tag_(tag), attr_(from_utf8(attr)), tagtype_(tagtype) {}
+       ///
+       explicit CompTag(docstring const & tag, docstring const & attr, std::string const & tagtype = "none")
+                       : tag_(tag), attr_(attr), tagtype_(tagtype) {}
        /// <tag_ attr_ />
        docstring writeTag() const;
        ///
-       std::string tag_;
+       docstring tag_;
        ///
-       std::string attr_;
+       docstring attr_;
+       /// Type of tag for new-line behaviour. Either "paragraph", "inline", "block", or "none" (default).
+       std::string tagtype_;
 };
 
 
 /// A special case of StartTag, used exclusively for tags that wrap paragraphs.
-/// parid is only used for HTML output; XML is supposed to use attr for this.
 struct ParTag : public StartTag
 {
        ///
        explicit ParTag(std::string const & tag, const std::string & attr): StartTag(tag, from_utf8(attr)) {}
        ///
-       ~ParTag() {}
+       ~ParTag() override = default;
 };
 
 
@@ -351,6 +382,41 @@ void closeTag(odocstream & os, std::string const & name);
 /// Close tag
 void closeTag(odocstream & os, Paragraph const & par);
 
+// Convenience functions to open and close tags. First, very low-level ones to ensure a consistent new-line behaviour.
+// Block style:
+//       Content before
+//       <blocktag>
+//         Contents of the block.
+//       </blocktag>
+//       Content after
+// Paragraph style:
+//       Content before
+//         <paratag>Contents of the paragraph.</paratag>
+//       Content after
+// Inline style:
+//    Content before<inlinetag>Contents of the paragraph.</inlinetag>Content after
+
+///
+void openTag(XMLStream & xs, const docstring & tag, const docstring & attr, const std::string & tagtype);
+///
+void openTag(XMLStream & xs, const std::string & tag, const std::string & attr, const std::string & tagtype);
+///
+void openTag(XMLStream & xs, const docstring & tag, const std::string & attr, const std::string & tagtype);
+///
+void openTag(XMLStream & xs, const std::string & tag, const docstring & attr, const std::string & tagtype);
+///
+void closeTag(XMLStream & xs, const docstring & tag, const std::string & tagtype);
+///
+void closeTag(XMLStream & xs, const std::string & tag, const std::string & tagtype);
+///
+void compTag(XMLStream & xs, const docstring & tag, const docstring & attr, const std::string & tagtype);
+///
+void compTag(XMLStream & xs, const std::string & tag, const std::string & attr, const std::string & tagtype);
+///
+void compTag(XMLStream & xs, const docstring & tag, const std::string & attr, const std::string & tagtype);
+///
+void compTag(XMLStream & xs, const std::string & tag, const docstring & attr, const std::string & tagtype);
+
 } // namespace xml
 
 } // namespace lyx