Doxygen
Loading...
Searching...
No Matches
dotgraph.cpp
Go to the documentation of this file.
1/******************************************************************************
2*
3* Copyright (C) 1997-2019 by Dimitri van Heesch.
4*
5* Permission to use, copy, modify, and distribute this software and its
6* documentation under the terms of the GNU General Public License is hereby
7* granted. No representations are made about the suitability of this software
8* for any purpose. It is provided "as is" without express or implied warranty.
9* See the GNU General Public License for more details.
10*
11* Documents produced by Doxygen are derivative works derived from the
12* input used in their production; they are not affected by this license.
13*
14*/
15
16#include <mutex>
17#include <regex>
18
19#include "config.h"
20#include "doxygen.h"
21#include "indexlist.h"
22#include "md5.h"
23#include "message.h"
24#include "util.h"
25
26#include "dot.h"
27#include "dotrunner.h"
28#include "dotgraph.h"
29#include "dotnode.h"
30#include "dotfilepatcher.h"
31#include "fileinfo.h"
32#include "portable.h"
33
34//QCString DotGraph::DOT_FONTNAME; // will be initialized in initDot
35//int DotGraph::DOT_FONTSIZE; // will be initialized in initDot
36
37/*! Checks if a file "baseName".md5 exists. If so the contents
38* are compared with \a md5. If equal FALSE is returned.
39* The .md5 is created or updated after successful creation of the output file.
40*/
41static bool sameMd5Signature(const QCString &baseName,
42 const QCString &md5)
43{
44 bool same = false;
45 char md5stored[33];
46 md5stored[0]=0;
47 std::ifstream f = Portable::openInputStream(baseName+".md5",true);
48 if (f.is_open())
49 {
50 // read checksum
51 f.read(md5stored,32);
52 md5stored[32]='\0';
53 // compare checksum
54 if (!f.fail() && md5==md5stored)
55 {
56 same = true;
57 }
58 //printf("sameSignature(%s,%s==%s)=%d\n",qPrint(baseName),md5stored,qPrint(md5),same);
59 }
60 else
61 {
62 //printf("sameSignature(%s) not found\n",qPrint(baseName));
63 }
64 return same;
65}
66
67static bool deliverablesPresent(const QCString &file1,const QCString &file2)
68{
69 bool file1Ok = true;
70 bool file2Ok = true;
71 if (!file1.isEmpty())
72 {
73 FileInfo fi(file1.str());
74 file1Ok = (fi.exists() && fi.size()>0);
75 }
76 if (!file2.isEmpty())
77 {
78 FileInfo fi(file2.str());
79 file2Ok = (fi.exists() && fi.size()>0);
80 }
81 return file1Ok && file2Ok;
82}
83
84static bool insertMapFile(TextStream &out,const QCString &mapFile,
85 const QCString &relPath,const QCString &mapLabel)
86{
87 FileInfo fi(mapFile.str());
88 if (fi.exists() && fi.size()>0) // reuse existing map file
89 {
90 TextStream t;
91 DotFilePatcher::convertMapFile(t,mapFile,relPath,false);
92 if (!t.empty())
93 {
94 out << "<map name=\"" << mapLabel << "\" id=\"" << mapLabel << "\">\n";
95 out << t.str();
96 out << "</map>\n";
97 }
98 return true;
99 }
100 return false; // no map file yet, need to generate it
101}
102
103//--------------------------------------------------------------------
104
106{
108 ("." + getDotImageExtension()) : (Config_getBool(USE_PDFLATEX) ? ".pdf" : ".eps"));
109}
110
112
114 TextStream& t, // output stream for the code file (html, ...)
115 GraphOutputFormat gf, // bitmap(png/svg) or ps(eps/pdf)
116 EmbeddedOutputFormat ef, // html, latex, ...
117 const QCString &path, // output folder
118 const QCString &fileName, // name of the code file (for code patcher)
119 const QCString &relPath, // output folder relative to code file
120 bool generateImageMap, // in case of bitmap, shall there be code generated?
121 int graphId) // number of this graph in the current code, used in svg code
122{
123 m_graphFormat = gf;
124 m_textFormat = ef;
125 m_dir = Dir(path.str());
126 m_fileName = fileName;
127 m_relPath = relPath;
128 m_generateImageMap = generateImageMap;
129 m_graphId = graphId;
130
131 m_absPath = m_dir.absPath() + "/";
133
135
137
139 {
140 std::lock_guard<std::mutex> lock(g_dotIndexListMutex);
141 Doxygen::indexList->addImageFile(imgName());
142 }
143
144 generateCode(t);
145
146 return m_baseName;
147}
148
150{
151 if (!m_dir.exists())
152 {
153 term("Output dir {} does not exist!\n", m_dir.path());
154 }
155
156 char sigStr[33];
157 uint8_t md5_sig[16];
158 // calculate md5
159 MD5Buffer(m_theGraph.data(), static_cast<unsigned int>(m_theGraph.length()), md5_sig);
160 // convert result to a string
161 MD5SigToString(md5_sig, sigStr);
162
163 // already queued files are processed again in case the output format has changed
164
165 if (sameMd5Signature(absBaseName(), sigStr) &&
168 )
169 )
170 {
171 // all needed files are there
172 return FALSE;
173 }
174
175 // need to rebuild the image
176
177 // write .dot file because image was new or has changed
178 std::ofstream f = Portable::openOutputStream(absDotName());
179 if (!f.is_open())
180 {
181 err("Could not open file {} for writing\n",absDotName());
182 return TRUE;
183 }
184 f << m_theGraph;
185 f.close();
186
188 {
189 // run dot to create a bitmap image
191 }
193 {
194 // run dot to create a .eps image
195 if (Config_getBool(USE_PDFLATEX))
196 {
197 DotManager::instance()->addJob(DotJob(m_absPath, m_baseName + ".dot", "pdf", sigStr, absDotName(), m_theGraph.size()));
198 }
199 else
200 {
201 DotManager::instance()->addJob(DotJob(m_absPath, m_baseName + ".dot", "eps", sigStr, absDotName(), m_theGraph.size()));
202 }
203 }
204 return TRUE;
205}
206
208{
211 {
212 t << "<para>\n";
213 t << " <informalfigure>\n";
214 t << " <mediaobject>\n";
215 t << " <imageobject>\n";
216 t << " <imagedata";
217 t << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << m_relPath << m_baseName << "." << imgExt << "\">";
218 t << "</imagedata>\n";
219 t << " </imageobject>\n";
220 t << " </mediaobject>\n";
221 t << " </informalfigure>\n";
222 t << "</para>\n";
223 }
224 else if (m_graphFormat==GraphOutputFormat::BITMAP && m_generateImageMap) // produce HTML to include the image
225 {
226 if (imgExt=="svg") // add link to SVG file without map file
227 {
228 if (!m_noDivTag) t << "<div class=\"center\">";
229 if (m_regenerate || !DotFilePatcher::writeSVGFigureLink(t,m_relPath,m_baseName,absImgName())) // need to patch the links in the generated SVG file
230 {
231 if (m_regenerate)
232 {
234 createFilePatcher(absImgName())->
235 addSVGConversion(m_relPath,FALSE,QCString(),m_zoomable,m_graphId);
236 }
237 int mapId = DotManager::instance()->
238 createFilePatcher(m_fileName)->
239 addSVGObject(m_baseName,absImgName(),m_relPath);
240 t << "<!-- " << "SVG " << mapId << " -->";
241 }
242 if (!m_noDivTag) t << "</div>\n";
243 }
244 else // add link to bitmap file with image map
245 {
246 if (!m_noDivTag) t << "<div class=\"center\">";
247 t << "<img src=\"" << relImgName() << "\" border=\"0\" usemap=\"#" << correctId(getMapLabel()) << "\" loading=\"lazy\" alt=\"" << getImgAltText() << "\"/>";
248 if (!m_noDivTag) t << "</div>";
249 t << "\n";
251 {
252 int mapId = DotManager::instance()->
253 createFilePatcher(m_fileName)->
255 t << "<!-- MAP " << mapId << " -->\n";
256 }
257 }
258 }
259 else if (m_graphFormat==GraphOutputFormat::EPS) // produce tex to include the .eps image
260 {
262 {
263 int figId = DotManager::instance()->
264 createFilePatcher(m_fileName)->
265 addFigure(m_baseName,absBaseName(),FALSE /*TRUE*/);
266 t << "\n% FIG " << figId << "\n";
267 }
268 }
269}
270
272{
273 t << "digraph ";
274 if (title.isEmpty())
275 {
276 t << "\"Dot Graph\"";
277 }
278 else
279 {
280 t << "\"" << convertToXML(title) << "\"";
281 }
282 t << "\n{\n";
283 if (Config_getBool(INTERACTIVE_SVG)) // insert a comment to force regeneration when this
284 // option is toggled
285 {
286 t << " // INTERACTIVE_SVG=YES\n";
287 }
288 t << " // LATEX_PDF_SIZE\n"; // write placeholder for LaTeX PDF bounding box size replacement
289 t << " bgcolor=\"transparent\";\n";
290 QCString c = Config_getString(DOT_COMMON_ATTR);
291 if (!c.isEmpty()) c += ",";
292 t << " edge [" << c << Config_getString(DOT_EDGE_ATTR) << "];\n";
293 t << " node [" << c << Config_getString(DOT_NODE_ATTR) << "];\n";
294}
295
297{
298 t << "}\n";
299}
300
302 GraphType gt,
303 GraphOutputFormat format,
304 const QCString &rank, // either "LR", "RL", or ""
305 bool renderParents,
306 bool backArrows,
307 const QCString &title,
308 QCString &graphStr)
309{
310 //printf("computeMd5Signature\n");
311 TextStream md5stream;
312 writeGraphHeader(md5stream,title);
313 if (!rank.isEmpty())
314 {
315 md5stream << " rankdir=\"" << rank << "\";\n";
316 }
317 root->clearWriteFlag();
318 root->write(md5stream, gt, format, gt!=GraphType::CallGraph && gt!=GraphType::Dependency, TRUE, backArrows);
319 if (renderParents)
320 {
321 for (const auto &pn : root->parents())
322 {
323 if (pn->isVisible())
324 {
325 const auto &children = pn->children();
326 auto child_it = std::find(children.begin(),children.end(),root);
327 size_t index = child_it - children.begin();
328 root->writeArrow(md5stream, // stream
329 gt, // graph type
330 format, // output format
331 pn, // child node
332 &pn->edgeInfo()[index], // edge info
333 FALSE, // topDown?
334 backArrows // point back?
335 );
336 }
337 pn->write(md5stream, // stream
338 gt, // graph type
339 format, // output format
340 TRUE, // topDown?
341 FALSE, // toChildren?
342 backArrows // backward pointing arrows?
343 );
344 }
345 }
346 writeGraphFooter(md5stream);
347
348 graphStr=md5stream.str();
349}
350
Class representing a directory in the file system.
Definition dir.h:75
static bool writeVecGfxFigure(TextStream &out, const QCString &baseName, const QCString &figureName)
static bool convertMapFile(TextStream &t, const QCString &mapName, const QCString &relPath, bool urlOnly=FALSE, const QCString &context=QCString())
static bool writeSVGFigureLink(TextStream &out, const QCString &relPath, const QCString &baseName, const QCString &absImgName)
Check if a reference to a SVG figure can be written and do so if possible.
QCString absBaseName() const
Definition dotgraph.h:78
bool m_noDivTag
Definition dotgraph.h:98
virtual QCString absMapName() const
Definition dotgraph.h:72
Dir m_dir
Definition dotgraph.h:87
int m_graphId
Definition dotgraph.h:91
static void computeGraph(DotNode *root, GraphType gt, GraphOutputFormat format, const QCString &rank, bool renderParents, bool backArrows, const QCString &title, QCString &graphStr)
Definition dotgraph.cpp:301
EmbeddedOutputFormat m_textFormat
Definition dotgraph.h:86
QCString imgName() const
Definition dotgraph.cpp:105
QCString m_fileName
Definition dotgraph.h:88
QCString absImgName() const
Definition dotgraph.h:81
static void writeGraphFooter(TextStream &t)
Definition dotgraph.cpp:296
bool m_urlOnly
Definition dotgraph.h:100
virtual QCString getBaseName() const =0
GraphOutputFormat m_graphFormat
Definition dotgraph.h:85
void generateCode(TextStream &t)
Definition dotgraph.cpp:207
bool prepareDotFile()
Definition dotgraph.cpp:149
static void writeGraphHeader(TextStream &t, const QCString &title=QCString())
Definition dotgraph.cpp:271
virtual QCString getImgAltText() const
Definition dotgraph.h:74
QCString relImgName() const
Definition dotgraph.h:82
QCString m_absPath
Definition dotgraph.h:93
virtual QCString getMapLabel() const =0
bool m_doNotAddImageToIndex
Definition dotgraph.h:97
bool m_regenerate
Definition dotgraph.h:96
bool m_zoomable
Definition dotgraph.h:99
QCString absDotName() const
Definition dotgraph.h:79
QCString m_theGraph
Definition dotgraph.h:95
QCString m_baseName
Definition dotgraph.h:94
QCString writeGraph(TextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef, const QCString &path, const QCString &fileName, const QCString &relPath, bool writeImageMap=TRUE, int graphId=-1)
Definition dotgraph.cpp:113
virtual void computeTheGraph()=0
friend class DotNode
Definition dotgraph.h:36
bool m_generateImageMap
Definition dotgraph.h:90
QCString m_relPath
Definition dotgraph.h:89
void addJob(const DotJob &newJob)
Definition dot.cpp:92
static DotManager * instance()
Definition dot.cpp:78
void write(TextStream &t, GraphType gt, GraphOutputFormat f, bool topDown, bool toChildren, bool backArrows)
Definition dotnode.cpp:654
void clearWriteFlag()
Definition dotnode.cpp:887
const DotNodeRefVector & parents() const
Definition dotnode.h:124
void writeArrow(TextStream &t, GraphType gt, GraphOutputFormat f, const DotNode *cn, const EdgeInfo *ei, bool topDown, bool pointBack=TRUE) const
Definition dotnode.cpp:603
static IndexList * indexList
Definition doxygen.h:132
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
bool exists() const
Definition fileinfo.cpp:30
size_t size() const
Definition fileinfo.cpp:23
This is an alternative implementation of QCString.
Definition qcstring.h:101
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
const std::string & str() const
Definition qcstring.h:552
Text streaming class that buffers data.
Definition textstream.h:36
bool empty() const
Returns true iff the buffer is empty.
Definition textstream.h:240
std::string str() const
Return the contents of the buffer as a std::string object.
Definition textstream.h:216
#define Config_getEnumAsString(name)
Definition config.h:36
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
static bool insertMapFile(TextStream &out, const QCString &mapFile, const QCString &relPath, const QCString &mapLabel)
Definition dotgraph.cpp:84
static bool sameMd5Signature(const QCString &baseName, const QCString &md5)
Definition dotgraph.cpp:41
static bool deliverablesPresent(const QCString &file1, const QCString &file2)
Definition dotgraph.cpp:67
std::mutex g_dotIndexListMutex
Definition dotgraph.cpp:111
GraphType
Definition dotgraph.h:31
@ Dependency
Definition dotgraph.h:31
@ CallGraph
Definition dotgraph.h:31
EmbeddedOutputFormat
Definition dotgraph.h:30
GraphOutputFormat
Definition dotgraph.h:29
#define err(fmt,...)
Definition message.h:127
#define term(fmt,...)
Definition message.h:137
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:659
std::ofstream openOutputStream(const QCString &name, bool append=false)
Definition portable.cpp:648
Portable versions of functions that are platform dependent.
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
QCString convertToXML(const QCString &s, bool keepEntities)
Definition util.cpp:3933
QCString correctId(const QCString &s)
Definition util.cpp:3926
QCString getDotImageExtension()
Definition util.cpp:6307
A bunch of utility functions.