Doxygen
Loading...
Searching...
No Matches
DotFilePatcher Class Reference

Helper class to insert a set of map file into an output file. More...

#include <src/dotfilepatcher.h>

Collaboration diagram for DotFilePatcher:

Classes

struct  Map

Public Member Functions

 DotFilePatcher (const QCString &patchFile)
int addMap (const QCString &mapFile, const QCString &relPath, bool urlOnly, const QCString &context, const QCString &label)
int addFigure (const QCString &baseName, const QCString &figureName, bool heightCheck)
int addSVGConversion (const QCString &relPath, bool urlOnly, const QCString &context, bool zoomable, int graphId)
int addSVGObject (const QCString &baseName, const QCString &figureName, const QCString &relPath)
bool run () const
bool isSVGFile () const

Static Public Member Functions

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.
static bool writeVecGfxFigure (TextStream &out, const QCString &baseName, const QCString &figureName)

Private Attributes

std::vector< Mapm_maps
QCString m_patchFile

Detailed Description

Helper class to insert a set of map file into an output file.

Definition at line 26 of file dotfilepatcher.h.

Constructor & Destructor Documentation

◆ DotFilePatcher()

DotFilePatcher::DotFilePatcher ( const QCString & patchFile)

Definition at line 256 of file dotfilepatcher.cpp.

257 : m_patchFile(patchFile)
258{
259}
QCString m_patchFile

References m_patchFile.

Member Function Documentation

◆ addFigure()

int DotFilePatcher::addFigure ( const QCString & baseName,
const QCString & figureName,
bool heightCheck )

Definition at line 274 of file dotfilepatcher.cpp.

276{
277 size_t id = m_maps.size();
278 m_maps.emplace_back(figureName,"",heightCheck,"",baseName);
279 return static_cast<int>(id);
280}
std::vector< Map > m_maps

References m_maps.

◆ addMap()

int DotFilePatcher::addMap ( const QCString & mapFile,
const QCString & relPath,
bool urlOnly,
const QCString & context,
const QCString & label )

Definition at line 266 of file dotfilepatcher.cpp.

268{
269 size_t id = m_maps.size();
270 m_maps.emplace_back(mapFile,relPath,urlOnly,context,label);
271 return static_cast<int>(id);
272}

References m_maps.

◆ addSVGConversion()

int DotFilePatcher::addSVGConversion ( const QCString & relPath,
bool urlOnly,
const QCString & context,
bool zoomable,
int graphId )

Definition at line 282 of file dotfilepatcher.cpp.

285{
286 size_t id = m_maps.size();
287 m_maps.emplace_back("",relPath,urlOnly,context,"",zoomable,graphId);
288 return static_cast<int>(id);
289}

References m_maps.

Referenced by writeDotImageMapFromFile().

◆ addSVGObject()

int DotFilePatcher::addSVGObject ( const QCString & baseName,
const QCString & figureName,
const QCString & relPath )

Definition at line 291 of file dotfilepatcher.cpp.

294{
295 size_t id = m_maps.size();
296 m_maps.emplace_back(absImgName,relPath,false,"",baseName);
297 return static_cast<int>(id);
298}

References m_maps.

◆ convertMapFile()

bool DotFilePatcher::convertMapFile ( TextStream & t,
const QCString & mapName,
const QCString & relPath,
bool urlOnly = FALSE,
const QCString & context = QCString() )
static

converts the rectangles in a client site image map into a stream

Parameters
tthe stream to which the result is written.
mapNamethe name of the map file.
relPaththe relative path to the root of the output directory (used in case CREATE_SUBDIRS is enabled).
urlOnlyif FALSE the url field in the map contains an external references followed by a $ and then the URL.
contextthe context (file, class, or namespace) in which the map file was found
Returns
TRUE if successful.

Definition at line 214 of file dotfilepatcher.cpp.

217{
218 std::ifstream f = Portable::openInputStream(mapName);
219 if (!f.is_open())
220 {
221 err("problems opening map file {} for inclusion in the docs!\n"
222 "If you installed Graphviz/dot after a previous failing run, \n"
223 "try deleting the output directory and rerun doxygen.\n",mapName);
224 return FALSE;
225 }
226 std::string line;
227 while (getline(f,line)) // foreach line
228 {
229 QCString buf = line+'\n';
230 if (buf.startsWith("<area"))
231 {
232 QCString replBuf = replaceRef(buf,relPath,urlOnly,context);
233 // in dot version 7.0.2 the alt attribute is, incorrectly, removed.
234 // see https://gitlab.com/graphviz/graphviz/-/issues/265
235 int indexA = replBuf.find("alt=");
236 if (indexA == -1)
237 {
238 replBuf = replBuf.left(5) + " alt=\"\"" + replBuf.right(replBuf.length() - 5);
239 }
240
241 // strip id="..." from replBuf since the id's are not needed and not unique.
242 int indexS = replBuf.find("id=\""), indexE = 0;
243 if (indexS>0 && (indexE=replBuf.find('"',indexS+4))!=-1)
244 {
245 t << replBuf.left(indexS-1) << replBuf.right(replBuf.length() - indexE - 1);
246 }
247 else
248 {
249 t << replBuf;
250 }
251 }
252 }
253 return TRUE;
254}
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:166
bool startsWith(const char *s) const
Definition qcstring.h:507
QCString right(size_t len) const
Definition qcstring.h:234
QCString left(size_t len) const
Definition qcstring.h:229
static QCString replaceRef(const QCString &buf, const QCString &relPath, bool urlOnly, const QCString &context, const QCString &target=QCString())
#define err(fmt,...)
Definition message.h:127
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:659
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34

References err, FALSE, QCString::find(), QCString::left(), QCString::length(), Portable::openInputStream(), replaceRef(), QCString::right(), QCString::startsWith(), and TRUE.

Referenced by insertMapFile(), run(), and writeDotImageMapFromFile().

◆ isSVGFile()

bool DotFilePatcher::isSVGFile ( ) const

Definition at line 261 of file dotfilepatcher.cpp.

262{
263 return m_patchFile.endsWith(".svg");
264}

References m_patchFile.

Referenced by run().

◆ run()

bool DotFilePatcher::run ( ) const

Definition at line 300 of file dotfilepatcher.cpp.

301{
302 //printf("DotFilePatcher::run(): %s\n",qPrint(m_patchFile));
303 bool interactiveSVG = Config_getBool(INTERACTIVE_SVG);
304 bool isSVGFile = m_patchFile.endsWith(".svg");
305 int graphId = -1;
306 QCString relPath;
307 if (isSVGFile)
308 {
309 const Map &map = m_maps.front(); // there is only one 'map' for a SVG file
310 interactiveSVG = interactiveSVG && map.zoomable;
311 graphId = map.graphId;
312 relPath = map.relPath;
313 //printf("DotFilePatcher::addSVGConversion: file=%s zoomable=%d\n",
314 // qPrint(m_patchFile),map->zoomable);
315 }
316 QCString tmpName = m_patchFile+".tmp";
317 Dir thisDir;
318 if (!thisDir.rename(m_patchFile.str(),tmpName.str()))
319 {
320 err("Failed to rename file {} to {}!\n",m_patchFile,tmpName);
321 return FALSE;
322 }
323 std::ifstream fi = Portable::openInputStream(tmpName);
324 std::ofstream fo = Portable::openOutputStream(m_patchFile);
325 if (!fi.is_open())
326 {
327 err("problem opening file {} for patching!\n",tmpName);
328 thisDir.rename(tmpName.str(),m_patchFile.str());
329 return FALSE;
330 }
331 if (!fo.is_open())
332 {
333 err("problem opening file {} for patching!\n",m_patchFile);
334 thisDir.rename(tmpName.str(),m_patchFile.str());
335 return FALSE;
336 }
337 TextStream t(&fo);
338 int width=0,height=0;
339 bool insideHeader=FALSE;
340 bool replacedHeader=FALSE;
341 bool useNagivation=FALSE;
342 std::string lineStr;
343 static const reg::Ex reSVG(R"([\‍[<]!-- SVG [0-9]+)");
344 static const reg::Ex reMAP(R"(<!-- MAP [0-9]+)");
345 static const reg::Ex reFIG(R"(% FIG [0-9]+)");
346
347 while (getline(fi,lineStr))
348 {
349 // replace id="page0,1_graph0" with id="graph0" to work around graphviz page numbering bug
350 {
351 auto pos = lineStr.find("id=\"page0,1_graph0\"");
352 if (pos != std::string::npos)
353 lineStr.replace(pos, 19, "id=\"graph0\"");
354 }
355 QCString line = lineStr+'\n';
356 //printf("line=[%s]\n",qPrint(line.stripWhiteSpace()));
357 int i = 0;
358 if (isSVGFile)
359 {
360 if (interactiveSVG)
361 {
362 if (line.find("<svg")!=-1 && !replacedHeader)
363 {
364 int count = sscanf(line.data(),"<svg width=\"%dpt\" height=\"%dpt\"",&width,&height);
365 if (count != 2) count = sscanf(line.data(),"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"%d\" height=\"%d\"",&width,&height);
366 //printf("width=%d height=%d\n",width,height);
367 useNagivation = count==2 && (width>500 || height>450);
368 insideHeader = count==2;
369 }
370 else if (insideHeader && !replacedHeader && line.find("<g id=\"graph")!=-1)
371 {
372 if (useNagivation)
373 {
374 // insert special replacement header for interactive SVGs
375 t << "<!--zoomable " << height << " -->\n";
376 t << svgZoomHeader0;
377 }
378 else
379 {
381 }
382 t << svgZoomHeader1;
383 if (useNagivation)
384 {
385 t << svgZoomHeader2;
386 }
387 t << "<script type=\"application/ecmascript\" xlink:href=\"" << relPath << "svg.min.js\"/>\n";
388 t << "<svg id=\"graph\" class=\"graph\"";
389 if (useNagivation)
390 {
391 t << " data-view-width=\"" << width << "\" data-view-height=\"" << height << "\"";
392 if (graphId>=0)
393 {
394 t << " data-section-id=\"dynsection-" << graphId << "\"";
395 }
396 }
397 t << ">\n";
398
399 if (useNagivation)
400 {
401 t << "<g id=\"viewport\">\n";
402 }
403 else
404 {
405 t << line;
406 }
407 line="";
408 insideHeader=FALSE;
409 replacedHeader=TRUE;
410 }
411 }
412 if (!insideHeader || !useNagivation) // copy SVG and replace refs,
413 // unless we are inside the header of the SVG.
414 // Then we replace it with another header.
415 {
416 const Map &map = m_maps.front(); // there is only one 'map' for a SVG file
417 t << replaceRef(line,map.relPath,map.urlOnly,map.context,"_top");
418 }
419 }
420 else if (line.find("SVG")!=-1 && (i=findIndex(line.str(),reSVG))!=-1)
421 {
422 //printf("Found marker at %d\n",i);
423 int mapId=-1;
424 t << line.left(i);
425 int n = sscanf(line.data()+i+1,"!-- SVG %d",&mapId);
426 if (n==1 && mapId>=0 && mapId<static_cast<int>(m_maps.size()))
427 {
428 int e = std::max(line.find("--]"),line.find("-->"));
429 const Map &map = m_maps.at(mapId);
430 //printf("DotFilePatcher::writeSVGFigure: file=%s zoomable=%d\n",
431 // qPrint(m_patchFile),map.zoomable);
432 if (!writeSVGFigureLink(t,map.relPath,map.label,map.mapFile))
433 {
434 err("Problem extracting size from SVG file {}\n",map.mapFile);
435 }
436 if (e!=-1) t << line.mid(e+3);
437 }
438 else // error invalid map id!
439 {
440 err("Found invalid SVG id in file {}!\n",m_patchFile);
441 t << line.mid(i);
442 }
443 }
444 else if (line.find("MAP")!=-1 && (i=findIndex(line.str(),reMAP))!=-1)
445 {
446 int mapId=-1;
447 t << line.left(i);
448 int n = sscanf(line.data()+i,"<!-- MAP %d",&mapId);
449 if (n==1 && mapId>=0 && mapId<static_cast<int>(m_maps.size()))
450 {
451 TextStream tt;
452 const Map &map = m_maps.at(mapId);
453 //printf("patching MAP %d in file %s with contents of %s\n",
454 // mapId,qPrint(m_patchFile),qPrint(map.mapFile));
455 convertMapFile(tt,map.mapFile,map.relPath,map.urlOnly,map.context);
456 if (!tt.empty())
457 {
458 t << "<map name=\"" << correctId(map.label) << "\" id=\"" << correctId(map.label) << "\">\n";
459 t << tt.str();
460 t << "</map>\n";
461 }
462 }
463 else // error invalid map id!
464 {
465 err("Found invalid MAP id in file {}!\n",m_patchFile);
466 t << line.mid(i);
467 }
468 }
469 else if (line.find("FIG")!=-1 && (i=findIndex(line.str(),reFIG))!=-1)
470 {
471 int mapId=-1;
472 int n = sscanf(line.data()+i+2,"FIG %d",&mapId);
473 //printf("line='%s' n=%d\n",qPrint(line)+i,n);
474 if (n==1 && mapId>=0 && mapId<static_cast<int>(m_maps.size()))
475 {
476 const Map &map = m_maps.at(mapId);
477 //printf("patching FIG %d in file %s with contents of %s\n",
478 // mapId,qPrint(m_patchFile),qPrint(map.mapFile));
479 if (!writeVecGfxFigure(t,map.label,map.mapFile))
480 {
481 err("problem writing FIG {} figure!\n",mapId);
482 return FALSE;
483 }
484 }
485 else // error invalid map id!
486 {
487 err("Found invalid bounding FIG {} in file {}!\n",mapId,m_patchFile);
488 t << line;
489 }
490 }
491 else
492 {
493 t << line;
494 }
495 }
496 if (isSVGFile && interactiveSVG && !useNagivation) t << "</svg>\n";
497
498 fi.close();
499 if (isSVGFile && interactiveSVG && replacedHeader)
500 {
501 QCString orgName=m_patchFile.left(m_patchFile.length()-4)+"_org.svg";
502 if (useNagivation)
503 {
504 t << substitute(svgZoomFooter1,"$orgname",stripPath(orgName));
505 }
506 t << svgZoomFooter2;
507 t.flush();
508 fo.close();
509 // keep original SVG file so we can refer to it, we do need to replace
510 // dummy link by real ones
511 fi = Portable::openInputStream(tmpName);
512 fo = Portable::openOutputStream(orgName);
513 if (!fi.is_open())
514 {
515 err("problem opening file {} for reading!\n",tmpName);
516 return FALSE;
517 }
518 if (!fo.is_open())
519 {
520 err("problem opening file {} for writing!\n",orgName);
521 return FALSE;
522 }
523 t.setStream(&fo);
524 while (getline(fi,lineStr)) // foreach line
525 {
526 QCString line = lineStr+'\n';
527 const Map &map = m_maps.front(); // there is only one 'map' for a SVG file
528 t << replaceRef(line,map.relPath,map.urlOnly,map.context,"_top");
529 }
530 t.flush();
531 fi.close();
532 fo.close();
533 }
534 // remove temporary file
535 thisDir.remove(tmpName.str());
536 return TRUE;
537}
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:314
bool rename(const std::string &orgName, const std::string &newName, bool acceptsAbsPath=true) const
Definition dir.cpp:321
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())
bool isSVGFile() const
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 mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:241
const std::string & str() const
Definition qcstring.h:552
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:172
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_getBool(name)
Definition config.h:33
static const char svgZoomHeader1[]
static const char svgZoomHeader2[]
static const char svgZoomHeader0_noinit[]
static const char svgZoomFooter2[]
static const char svgZoomHeader0[]
static const char svgZoomFooter1[]
std::ofstream openOutputStream(const QCString &name, bool append=false)
Definition portable.cpp:648
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:571
QCString stripPath(const QCString &s)
Definition util.cpp:4969
int findIndex(const StringVector &sv, const std::string &s)
find the index of a string in a vector of strings, returns -1 if the string could not be found
Definition util.cpp:6672
QCString correctId(const QCString &s)
Definition util.cpp:3926

References Config_getBool, DotFilePatcher::Map::context, convertMapFile(), correctId(), QCString::data(), TextStream::empty(), err, FALSE, QCString::find(), findIndex(), TextStream::flush(), DotFilePatcher::Map::graphId, isSVGFile(), DotFilePatcher::Map::label, QCString::left(), m_maps, m_patchFile, DotFilePatcher::Map::mapFile, QCString::mid(), Portable::openInputStream(), Portable::openOutputStream(), DotFilePatcher::Map::relPath, Dir::remove(), Dir::rename(), replaceRef(), TextStream::setStream(), QCString::str(), TextStream::str(), stripPath(), substitute(), svgZoomFooter1, svgZoomFooter2, svgZoomHeader0, svgZoomHeader0_noinit, svgZoomHeader1, svgZoomHeader2, TRUE, DotFilePatcher::Map::urlOnly, writeSVGFigureLink(), writeVecGfxFigure(), and DotFilePatcher::Map::zoomable.

Referenced by writeDotImageMapFromFile().

◆ writeSVGFigureLink()

bool DotFilePatcher::writeSVGFigureLink ( TextStream & out,
const QCString & relPath,
const QCString & baseName,
const QCString & absImgName )
static

Check if a reference to a SVG figure can be written and do so if possible.

Returns FALSE if not possible (for instance because the SVG file is not yet generated).

Definition at line 580 of file dotfilepatcher.cpp.

582{
583 int width=600,height=600;
584 if (!readSVGSize(absImgName,&width,&height))
585 {
586 return FALSE;
587 }
588 if (width==-1)
589 {
590 if (height<=60) height=300; else height+=300; // add some extra space for zooming
591 if (height>600) height=600; // clip to maximum height of 600 pixels
592 out << "<div class=\"zoom\">";
593 //out << "<object type=\"image/svg+xml\" data=\""
594 //out << "<embed type=\"image/svg+xml\" src=\""
595 out << "<iframe scrolling=\"no\" loading=\"lazy\" frameborder=\"0\" src=\""
596 << relPath << baseName << ".svg\" width=\"100%\" height=\"" << height << "\">";
597 }
598 else
599 {
600 //out << "<object type=\"image/svg+xml\" data=\""
601 //out << "<embed type=\"image/svg+xml\" src=\""
602 out << "<iframe scrolling=\"no\" loading=\"lazy\" frameborder=\"0\" src=\""
603 << relPath << baseName << ".svg\" width=\""
604 << ((width*96+48)/72) << "\" height=\""
605 << ((height*96+48)/72) << "\">";
606 }
608 //out << "</object>";
609 //out << "</embed>";
610 out << "</iframe>";
611 if (width==-1)
612 {
613 out << "</div>";
614 }
615
616 return TRUE;
617}
static bool readSVGSize(const QCString &fileName, int *width, int *height)
static void writeSVGNotSupported(TextStream &out)

References FALSE, readSVGSize(), TRUE, and writeSVGNotSupported().

Referenced by DotGraph::generateCode(), run(), and writeDotImageMapFromFile().

◆ writeVecGfxFigure()

bool DotFilePatcher::writeVecGfxFigure ( TextStream & out,
const QCString & baseName,
const QCString & figureName )
static

Definition at line 619 of file dotfilepatcher.cpp.

621{
622 int width=400,height=550;
623 if (Config_getBool(USE_PDFLATEX))
624 {
625 if (!DotRunner::readBoundingBox(figureName+".pdf",&width,&height,FALSE))
626 {
627 //printf("writeVecGfxFigure()=0\n");
628 return FALSE;
629 }
630 }
631 else
632 {
633 if (!DotRunner::readBoundingBox(figureName+".eps",&width,&height,TRUE))
634 {
635 //printf("writeVecGfxFigure()=0\n");
636 return FALSE;
637 }
638 }
639 //printf("Got PDF/EPS size %d,%d\n",width,height);
640 int maxWidth = 350; /* approx. page width in points, excl. margins */
641 int maxHeight = 550; /* approx. page height in points, excl. margins */
642 out << "\\nopagebreak\n"
643 "\\begin{figure}[H]\n"
644 "\\begin{center}\n"
645 "\\leavevmode\n";
646 if (width>maxWidth || height>maxHeight) // figure too big for page
647 {
648 // c*width/maxWidth > c*height/maxHeight, where c=maxWidth*maxHeight>0
649 if (width*maxHeight>height*maxWidth)
650 {
651 out << "\\includegraphics[width=" << maxWidth << "pt]";
652 }
653 else
654 {
655 out << "\\includegraphics[height=" << maxHeight << "pt]";
656 }
657 }
658 else
659 {
660 out << "\\includegraphics[width=" << width << "pt]";
661 }
662
663 out << "{" << baseName << "}\n"
664 "\\end{center}\n"
665 "\\end{figure}\n";
666
667 //printf("writeVecGfxFigure()=1\n");
668 return TRUE;
669}
static bool readBoundingBox(const QCString &fileName, int *width, int *height, bool isEps)

References Config_getBool, FALSE, DotRunner::readBoundingBox(), and TRUE.

Referenced by DotGraph::generateCode(), and run().

Member Data Documentation

◆ m_maps

std::vector<Map> DotFilePatcher::m_maps
private

Definition at line 69 of file dotfilepatcher.h.

Referenced by addFigure(), addMap(), addSVGConversion(), addSVGObject(), and run().

◆ m_patchFile

QCString DotFilePatcher::m_patchFile
private

Definition at line 70 of file dotfilepatcher.h.

Referenced by DotFilePatcher(), isSVGFile(), and run().


The documentation for this class was generated from the following files: