xref: /aosp_15_r20/external/image_io/src/xml/xml_writer.cc (revision ca0779eb572efbbfda2e47f806647c3c7eeea8c3)
1 #include "image_io/xml/xml_writer.h"
2 
3 #include <iomanip>
4 #include <string>
5 
6 namespace photos_editing_formats {
7 namespace image_io {
8 
9 using std::ostream;
10 using std::string;
11 using std::vector;
12 
13 namespace {
14 
15 const char kXmlnsColon[] = "xmlns:";
16 
17 }  // namespace
18 
XmlWriter(std::ostream & os)19 XmlWriter::XmlWriter(std::ostream& os)
20     : os_(os), element_count_(0), quote_mark_('"') {}
21 
WriteXmlns(const string & prefix,const string & uri)22 void XmlWriter::WriteXmlns(const string& prefix, const string& uri) {
23   string name = string(kXmlnsColon) + prefix;
24   WriteAttributeNameAndValue(name, uri, true);
25 }
26 
StartWritingElement(const string & element_name)27 size_t XmlWriter::StartWritingElement(const string& element_name) {
28   MaybeWriteCloseBracket(true);
29   size_t current_depth = element_data_.size();
30   if (current_depth > 0) {
31     element_data_.back().has_children = true;
32   }
33   element_data_.emplace_back(element_name);
34   os_ << indent_ << "<" << element_name;
35   indent_ += "  ";
36   element_count_ += 1;
37   return current_depth;
38 }
39 
FinishWritingElement()40 void XmlWriter::FinishWritingElement() {
41   if (!element_data_.empty()) {
42     if (indent_.size() >= 2) {
43       indent_.resize(indent_.size() - 2);
44     }
45     auto& data = element_data_.back();
46     if (!data.has_content && !data.has_children) {
47       if (!data.has_attributes || data.has_children) {
48         os_ << indent_;
49       }
50       os_ << "/>" << std::endl;
51     } else {
52       if (!data.has_content) {
53         os_ << indent_;
54       }
55       os_ << "</" << data.name << ">" << std::endl;
56     }
57     element_data_.pop_back();
58   }
59 }
60 
FinishWritingElementsToDepth(size_t depth)61 void XmlWriter::FinishWritingElementsToDepth(size_t depth) {
62   if (!element_data_.empty()) {
63     for (size_t index = element_data_.size(); index > depth; --index) {
64       FinishWritingElement();
65     }
66   }
67 }
68 
StartWritingElements(const vector<string> & element_names)69 size_t XmlWriter::StartWritingElements(const vector<string>& element_names) {
70   size_t current_depth = element_data_.size();
71   for (const auto& element_name : element_names) {
72     StartWritingElement(element_name);
73   }
74   return current_depth;
75 }
76 
WriteElementAndContent(const string & element_name,const string & content)77 void XmlWriter::WriteElementAndContent(const string& element_name,
78                                        const string& content) {
79   StartWritingElement(element_name);
80   WriteContent(content);
81   FinishWritingElement();
82 }
83 
WriteContent(const string & content)84 void XmlWriter::WriteContent(const string& content) {
85   MaybeWriteCloseBracket(false);
86   if (!element_data_.empty()) {
87     auto& data = element_data_.back();
88     data.has_content = true;
89     os_ << content;
90   }
91 }
92 
WriteAttributeNameAndValue(const string & name,const string & value,bool add_quote_marks)93 void XmlWriter::WriteAttributeNameAndValue(const string& name,
94                                            const string& value,
95                                            bool add_quote_marks) {
96   WriteAttributeName(name);
97   WriteAttributeValue(add_quote_marks, value, add_quote_marks);
98 }
99 
WriteAttributeName(const string & name)100 void XmlWriter::WriteAttributeName(const string& name) {
101   if (!element_data_.empty()) {
102     os_ << std::endl << indent_ << name << "=";
103     element_data_.back().has_attributes = true;
104   }
105 }
106 
WriteAttributeValue(bool add_leading_quote_mark,const string & value,bool add_trailing_quote_mark)107 void XmlWriter::WriteAttributeValue(bool add_leading_quote_mark,
108                                     const string& value,
109                                     bool add_trailing_quote_mark) {
110   if (!element_data_.empty()) {
111     if (add_leading_quote_mark) os_ << quote_mark_;
112     os_ << value;
113     if (add_trailing_quote_mark) os_ << quote_mark_;
114   }
115 }
116 
WriteComment(const std::string & comment)117 void XmlWriter::WriteComment(const std::string& comment) {
118   MaybeWriteCloseBracket(true);
119   os_ << indent_ << "<!-- " << comment << " -->" << std::endl;
120   if (!element_data_.empty()) {
121     auto& data = element_data_.back();
122     data.has_children = true;
123   }
124 }
125 
MaybeWriteCloseBracket(bool with_trailing_newline)126 bool XmlWriter::MaybeWriteCloseBracket(bool with_trailing_newline) {
127   if (!element_data_.empty()) {
128     auto& data = element_data_.back();
129     if (!data.has_content && !data.has_children) {
130       os_ << ">";
131       if (with_trailing_newline) {
132         os_ << std::endl;
133       }
134       return true;
135     }
136   }
137   return false;
138 }
139 
140 }  // namespace image_io
141 }  // namespace photos_editing_formats
142