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 256 of file dotfilepatcher.cpp.

257 : m_patchFile(patchFile)
258{
259}

References m_patchFile.

Member Function Documentation

◆ addFigure()

int DotFilePatcher::addFigure ( const DString & baseName,
const DString & 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 DString & mapFile,
const DString & relPath,
bool urlOnly,
const DString & context,
const DString & 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 DString & relPath,
bool urlOnly,
const DString & 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 DString & baseName,
const DString & figureName,
const DString & 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 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 215 of file dotfilepatcher.cpp.

218{
219 std::ifstream f = Portable::openInputStream(mapName);
220 if (!f.is_open())
221 {
222 err("problems opening map file {} for inclusion in the docs!\n"
223 "If you installed Graphviz/dot after a previous failing run, \n"
224 "try deleting the output directory and rerun doxygen.\n",mapName);
225 return false;
226 }
227 std::string line;
228 while (getline(f,line)) // foreach line
229 {
230 DString buf = line+'\n';
231 if (buf.startsWith("<area"))
232 {
233 DString replBuf = replaceRef(buf,relPath,urlOnly,context);
234 // in dot version 7.0.2 the alt attribute is, incorrectly, removed.
235 // see https://gitlab.com/graphviz/graphviz/-/issues/265
236 if (size_t indexA = replBuf.find("alt="); indexA==DString::npos)
237 {
238 replBuf = replBuf.left(5) + " alt=\"\"" + replBuf.mid(5);
239 }
240
241 // strip id="..." from replBuf since the id's are not needed and not unique.
242 if (size_t indexS = replBuf.find("id=\""), indexE = 0;
243 indexS!=DString::npos && indexS>0 && (indexE=replBuf.find('"',indexS+4))!=DString::npos)
244 {
245 t << replBuf.left(indexS-1) << replBuf.mid(indexE+1);
246 }
247 else
248 {
249 t << replBuf;
250 }
251 }
252 }
253 return true;
254}
DString mid(size_t index, size_t len=npos) const
Definition dstring.h:322
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:182
size_t find(char c, size_t pos=0) const
Definition dstring.h:243
DString left(size_t len) const
Definition dstring.h:310
bool startsWith(const char *s) const
Definition dstring.h:604
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:676

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 261 of file dotfilepatcher.cpp.

262{
263 return m_patchFile.endsWith(".svg");
264}
bool endsWith(const char *s) const
Definition dstring.h:621

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:152

References DString::empty().

Referenced by DotGraph::generateCode(), and 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 DString 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 DString 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 DString line = lineStr+'\n';
356 //printf("line=[%s]\n",qPrint(line.stripWhiteSpace()));
357 size_t i = 0;
358 if (isSVGFile)
359 {
360 if (interactiveSVG)
361 {
362 if (line.find("<svg")!=DString::npos && !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")!=DString::npos)
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")!=DString::npos && (i=findIndex(line.str(),reSVG))!=std::string::npos)
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 size_t e0 = line.find("--]");
429 size_t e1 = line.find("-->");
430 size_t e = e0!=DString::npos && e1!=DString::npos ? std::max(e0,e1) :
431 e0!=DString::npos ? e0 : e1;
432 const Map &map = m_maps.at(mapId);
433 //printf("DotFilePatcher::writeSVGFigure: file=%s zoomable=%d\n",
434 // qPrint(m_patchFile),map.zoomable);
435 if (!writeSVGFigureLink(t,map.relPath,map.label,map.mapFile))
436 {
437 err("Problem extracting size from SVG file {}\n",map.mapFile);
438 }
439 if (e!=DString::npos) t << line.mid(e+3);
440 }
441 else // error invalid map id!
442 {
443 err("Found invalid SVG id in file {}!\n",m_patchFile);
444 t << line.mid(i);
445 }
446 }
447 else if (line.find("MAP")!=DString::npos && (i=findIndex(line.str(),reMAP))!=std::string::npos)
448 {
449 int mapId=-1;
450 t << line.left(i);
451 int n = sscanf(line.data()+i,"<!-- MAP %d",&mapId);
452 if (n==1 && mapId>=0 && mapId<static_cast<int>(m_maps.size()))
453 {
454 TextStream tt;
455 const Map &map = m_maps.at(mapId);
456 //printf("patching MAP %d in file %s with contents of %s\n",
457 // mapId,qPrint(m_patchFile),qPrint(map.mapFile));
458 convertMapFile(tt,map.mapFile,map.relPath,map.urlOnly,map.context);
459 if (!tt.empty())
460 {
461 t << "<map name=\"" << mapLabelToId(map.label) << "\" id=\"" << mapLabelToId(map.label) << "\">\n";
462 t << tt.str();
463 t << "</map>\n";
464 }
465 }
466 else // error invalid map id!
467 {
468 err("Found invalid MAP id in file {}!\n",m_patchFile);
469 t << line.mid(i);
470 }
471 }
472 else if (line.find("FIG")!=DString::npos && (i=findIndex(line.str(),reFIG))!=std::string::npos)
473 {
474 int mapId=-1;
475 int n = sscanf(line.data()+i+2,"FIG %d",&mapId);
476 //printf("line='%s' n=%d\n",qPrint(line)+i,n);
477 if (n==1 && mapId>=0 && mapId<static_cast<int>(m_maps.size()))
478 {
479 const Map &map = m_maps.at(mapId);
480 //printf("patching FIG %d in file %s with contents of %s\n",
481 // mapId,qPrint(m_patchFile),qPrint(map.mapFile));
482 if (!writeVecGfxFigure(t,map.label,map.mapFile))
483 {
484 err("problem writing FIG {} figure!\n",mapId);
485 return false;
486 }
487 }
488 else // error invalid map id!
489 {
490 err("Found invalid bounding FIG {} in file {}!\n",mapId,m_patchFile);
491 t << line;
492 }
493 }
494 else
495 {
496 t << line;
497 }
498 }
499 if (isSVGFile && interactiveSVG && !useNagivation) t << "</svg>\n";
500
501 fi.close();
502 if (isSVGFile && interactiveSVG && replacedHeader)
503 {
504 DString orgName=m_patchFile.left(m_patchFile.length()-4)+"_org.svg";
505 if (useNagivation)
506 {
507 t << substitute(svgZoomFooter1,"$orgname",stripPath(orgName));
508 }
509 t << svgZoomFooter2;
510 t.flush();
511 fo.close();
512 // keep original SVG file so we can refer to it, we do need to replace
513 // dummy link by real ones
514 fi = Portable::openInputStream(tmpName);
515 fo = Portable::openOutputStream(orgName);
516 if (!fi.is_open())
517 {
518 err("problem opening file {} for reading!\n",tmpName);
519 return false;
520 }
521 if (!fo.is_open())
522 {
523 err("problem opening file {} for writing!\n",orgName);
524 return false;
525 }
526 t.setStream(&fo);
527 while (getline(fi,lineStr)) // foreach line
528 {
529 DString line = lineStr+'\n';
530 const Map &map = m_maps.front(); // there is only one 'map' for a SVG file
531 t << replaceRef(line,map.relPath,map.urlOnly,map.context,"_top");
532 }
533 t.flush();
534 fi.close();
535 fo.close();
536 }
537 // remove temporary file
538 thisDir.remove(tmpName.str());
539 return true;
540}
const std::string & str() const
Definition dstring.h:649
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:161
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition dstring.h:155
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:315
bool rename(const std::string &orgName, const std::string &newName, bool acceptsAbsPath=true) const
Definition dir.cpp:322
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:481
std::ofstream openOutputStream(const DString &name, bool append=false)
Definition portable.cpp:665
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:3962

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 583 of file dotfilepatcher.cpp.

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

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