Escape angle brackets in dot file labels
[platform/upstream/armnn.git] / src / armnnUtils / DotSerializer.cpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "DotSerializer.hpp"
7
8 #include <boost/assert.hpp>
9 #include <boost/algorithm/string/replace.hpp>
10 #include <sstream>
11 #include <cstring>
12
13 namespace armnn
14 {
15
16 namespace
17 {
18 std::string Indent(int numSpaces)
19 {
20     std::stringstream ss;
21     for (int i = 0; i < numSpaces; i++)
22     {
23         ss << " ";
24     }
25     return ss.str();
26 }
27
28 std::string Escape(std::string s)
29 {
30     boost::replace_all(s, "<", "\\<");
31     boost::replace_all(s, ">", "\\>");
32     return s;
33 }
34
35 } //namespace
36
37
38 HtmlFont::HtmlFont(std::ostream& stream, int fontSize, const char *color, const char *face)
39     : DotBase(stream)
40 {
41     GetStream() << "<FONT";
42
43     if (fontSize > -1)
44     {
45         GetStream() << " POINT-SIZE=" << "\"" << fontSize << "\"";
46     }
47
48     if (color && std::strlen(color) != 0)
49     {
50         GetStream() << " COLOR=\"" << color << "\" ";
51     }
52
53     if (face && std::strlen(face) != 0)
54     {
55         GetStream() << " FACE=\"" << face << "\" ";
56     }
57
58     GetStream() << ">";
59 }
60
61
62 HtmlFont::HtmlFont(std::ostream& stream)
63     : HtmlFont(stream, -1, nullptr, nullptr)
64 {}
65
66 HtmlFont::~HtmlFont()
67 {
68     GetStream() << "</FONT>";
69 }
70
71
72 DotAttributeSet::DotAttributeSet(std::ostream& stream)
73     : DotBase(stream)
74 {
75     GetStream() << "[";
76 }
77
78 DotAttributeSet::~DotAttributeSet()
79 {
80     bool doSpace=false;
81     for (auto&& attrib : m_Attributes)
82     {
83         if (doSpace)
84         {
85             GetStream() << " ";
86         }
87
88         GetStream() << attrib;
89         doSpace=true;
90     }
91
92     GetStream() << "]";
93 }
94
95 DotAttributeSet & DotAttributeSet::AddAttribute(const std::string& name, const std::stringstream& value)
96 {
97     std::stringstream ss;
98     ss << name <<"=" << value.str();
99     m_Attributes.push_back(ss.str());
100     return *this;
101 }
102
103 DotAttributeSet & DotAttributeSet::AddAttribute(const std::string& name, int value)
104 {
105     std::stringstream ss;
106     ss << name <<"=" << value;
107     m_Attributes.push_back(ss.str());
108     return *this;
109 }
110
111 DotAttributeSet & DotAttributeSet::AddAttribute(const std::string& name, const std::string& value)
112 {
113     std::stringstream ss;
114     ss << name <<"=\"" << value << "\"";
115     m_Attributes.push_back(ss.str());
116     return *this;
117 }
118
119 DotEdge::DotEdge(std::ostream& stream, unsigned int fromNodeId, unsigned int toNodeId)
120     : DotBase(stream)
121 {
122     std::stringstream ss;
123     ss << Indent(4) << fromNodeId << " -> " << toNodeId << " ";
124     GetStream() << ss.str();
125
126     m_Attributes = std::make_unique<DotAttributeSet>(stream);
127 }
128
129 DotEdge::~DotEdge()
130 {
131     m_Attributes.reset(nullptr);
132     GetStream() << ";" << std::endl;
133 }
134
135
136 NodeContent::NodeContent(std::ostream& stream)
137     : DotBase(stream)
138 {
139 }
140
141 NodeContent & NodeContent::SetName(const std::string & name)
142 {
143     m_Name = name;
144     return *this;
145 }
146
147 NodeContent & NodeContent::AddContent(const std::string & content)
148 {
149     m_Contents.push_back(content);
150     return *this;
151 }
152
153 NodeContent::~NodeContent()
154 {
155     std::stringstream ss;
156     ss << "label=\"{" << m_Name;
157     if (!m_Contents.empty())
158     {
159         ss << "|";
160     }
161     for (auto & content : m_Contents)
162     {
163         ss << Escape(content);
164         ss << "\\l";
165     }
166     ss << "}\"";
167
168     std::string s;
169     try
170     {
171         // Coverity fix: std::stringstream::str() may throw an exception of type std::length_error.
172         s = ss.str();
173     }
174     catch (const std::exception&) { } // Swallow any exception.
175
176     GetStream() << s;
177 }
178
179 DotNode::DotNode(std::ostream& stream, unsigned int nodeId, const char* label)
180     : DotBase(stream)
181 {
182     std::stringstream ss;
183     ss << Indent(4) << nodeId;
184
185     GetStream() << ss.str() << " ";
186
187     m_Contents = std::make_unique<NodeContent>(stream);
188     m_Attributes = std::make_unique<DotAttributeSet>(stream);
189
190     if (std::strlen(label) != 0)
191     {
192         m_Contents->SetName(label);
193     }
194     else
195     {
196         m_Contents->SetName("<noname>");
197     }
198 }
199
200 DotNode::~DotNode()
201 {
202     m_Contents.reset(nullptr);
203     m_Attributes.reset(nullptr);
204     GetStream() << ";" << std::endl;
205 }
206
207
208 DotDefaults::DotDefaults(std::ostream& stream, const char* type)
209     : DotBase(stream)
210 {
211     std::stringstream ss;
212     ss << Indent(4) << type;
213
214     GetStream() << ss.str() << " ";
215     m_Attributes = std::make_unique<DotAttributeSet>(stream);
216 }
217
218 DotDefaults::~DotDefaults()
219 {
220     m_Attributes.reset(nullptr);
221     GetStream() << ";" << std::endl;
222 }
223
224 DotGraph::DotGraph(std::ostream& stream, const char* name)
225     : DotBase(stream)
226 {
227     GetStream() << "digraph " << name << " {" << std::endl;
228 }
229
230 DotGraph::~DotGraph()
231 {
232     GetStream() << "}" << std::endl;
233 }
234
235 } //namespace armnn
236
237