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 DString &patchFile)
int addMap (const DString &mapFile, const DString &relPath, bool urlOnly, const DString &context, const DString &label)
int addFigure (const DString &baseName, const DString &figureName, bool heightCheck)
int addSVGConversion (const DString &relPath, bool urlOnly, const DString &context, bool zoomable, int graphId)
int addSVGObject (const DString &baseName, const DString &figureName, const DString &relPath)
bool run () const
bool isSVGFile () const

Static Public Member Functions

static bool convertMapFile (TextStream &t, const DString &mapName, const DString &relPath, bool urlOnly=false, const DString &context=DString())
static bool writeSVGFigureLink (TextStream &out, const DString &relPath, const DString &baseName, const DString &absImgName)
 Check if a reference to a SVG figure can be written and do so if possible.
static bool writeVecGfxFigure (TextStream &out, const DString &baseName, const DString &figureName)
static DString mapLabelToId (const DString &mapLabel)

Private Attributes

std::vector< Mapm_maps
DString 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 DString & patchFile)

Definition at line 258 of file dotfilepatcher.cpp.

259 : m_patchFile(patchFile)
260{
261}

References m_patchFile.

Member Function Documentation

◆ addFigure()

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

Definition at line 276 of file dotfilepatcher.cpp.

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

References m_maps.

◆ addMap()

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

Definition at line 268 of file dotfilepatcher.cpp.

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

References m_maps.

◆ addSVGConversion()

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

Definition at line 284 of file dotfilepatcher.cpp.

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

References m_maps.

Referenced by writeDotImageMapFromFile().

◆ addSVGObject()

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

Definition at line 293 of file dotfilepatcher.cpp.

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

References m_maps.

◆ convertMapFile()

bool DotFilePatcher::convertMapFile ( TextStream & t,
const DString & mapName,
const DString & relPath,
bool urlOnly = false,
const DString & context = DString() )
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 217 of file dotfilepatcher.cpp.

220{
221 std::ifstream f = Portable::openInputStream(mapName);
222 if (!f.is_open())
223 {
224 err("problems opening map file {} for inclusion in the docs!\n"
225 "If you installed Graphviz/dot after a previous failing run, \n"
226 "try deleting the output directory and rerun doxygen.\n",mapName);
227 return false;
228 }
229 std::string line;
230 while (getline(f,line)) // foreach line
231 {
232 DString buf = line+'\n';
233 if (buf.startsWith("<area"))
234 {
235 DString replBuf = replaceRef(buf,relPath,urlOnly,context);
236 // in dot version 7.0.2 the alt attribute is, incorrectly, removed.
237 // see https://gitlab.com/graphviz/graphviz/-/issues/265
238 if (size_t indexA = replBuf.find("alt="); indexA==DString::npos)
239 {
240 replBuf = replBuf.left(5) + " alt=\"\"" + replBuf.mid(5);
241 }
242
243 // strip id="..." from replBuf since the id's are not needed and not unique.
244 if (size_t indexS = replBuf.find("id=\""), indexE = 0;
245 indexS!=DString::npos && indexS>0 && (indexE=replBuf.find('"',indexS+4))!=DString::npos)
246 {
247 t << replBuf.left(indexS-1) << replBuf.mid(indexE+1);
248 }
249 else
250 {
251 t << replBuf;
252 }
253 }
254 }
255 return true;
256}
DString mid(size_t index, size_t len=npos) const
Definition dstring.h:318
static constexpr size_t npos
value used to indicate 'not found' or 'to the end of the string', matching std::string::npos
Definition dstring.h:178
size_t find(char c, size_t pos=0) const
Definition dstring.h:239
DString left(size_t len) const
Definition dstring.h:306
bool startsWith(const char *s) const
Definition dstring.h:600
static DString replaceRef(const DString &buf, const DString &relPath, bool urlOnly, const DString &context, const DString &target=DString())
#define err(fmt,...)
Definition message.h:127
std::ifstream openInputStream(const DString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:692

References err, DString::find(), DString::left(), DString::mid(), DString::npos, Portable::openInputStream(), replaceRef(), and DString::startsWith().

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

◆ isSVGFile()

bool DotFilePatcher::isSVGFile ( ) const

Definition at line 263 of file dotfilepatcher.cpp.

264{
265 return m_patchFile.endsWith(".svg");
266}
bool endsWith(const char *s) const
Definition dstring.h:617

References DString::endsWith(), and m_patchFile.

Referenced by run().

◆ mapLabelToId()

DString DotFilePatcher::mapLabelToId ( const DString & mapLabel)
inlinestatic

To adhere to the requirement that an id cannot have a digit at the first position always place an "a" in front

Definition at line 55 of file dotfilepatcher.h.

56 {
57 if (mapLabel.empty()) return mapLabel;
58 return "a" + mapLabel;
59 }
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:148

References DString::empty().

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

◆ run()

bool DotFilePatcher::run ( ) const

Definition at line 302 of file dotfilepatcher.cpp.

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

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

Referenced by writeDotImageMapFromFile().

◆ writeSVGFigureLink()

bool DotFilePatcher::writeSVGFigureLink ( TextStream & out,
const DString & relPath,
const DString & baseName,
const DString & 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 585 of file dotfilepatcher.cpp.

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

References readSVGSize(), and writeSVGNotSupported().

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

◆ writeVecGfxFigure()

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

Definition at line 624 of file dotfilepatcher.cpp.

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

References Config_getBool, and DotRunner::readBoundingBox().

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

Member Data Documentation

◆ m_maps

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

Definition at line 76 of file dotfilepatcher.h.

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

◆ m_patchFile

DString DotFilePatcher::m_patchFile
private

Definition at line 77 of file dotfilepatcher.h.

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


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