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

263 : m_patchFile(patchFile)
264{
265}
QCString m_patchFile

References m_patchFile.

Member Function Documentation

◆ addFigure()

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

Definition at line 280 of file dotfilepatcher.cpp.

282{
283 size_t id = m_maps.size();
284 m_maps.emplace_back(figureName,"",heightCheck,"",baseName);
285 return static_cast<int>(id);
286}
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 272 of file dotfilepatcher.cpp.

274{
275 size_t id = m_maps.size();
276 m_maps.emplace_back(mapFile,relPath,urlOnly,context,label);
277 return static_cast<int>(id);
278}

References m_maps.

◆ addSVGConversion()

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

Definition at line 288 of file dotfilepatcher.cpp.

291{
292 size_t id = m_maps.size();
293 m_maps.emplace_back("",relPath,urlOnly,context,"",zoomable,graphId);
294 return static_cast<int>(id);
295}

References m_maps.

Referenced by writeDotImageMapFromFile().

◆ addSVGObject()

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

Definition at line 297 of file dotfilepatcher.cpp.

300{
301 size_t id = m_maps.size();
302 m_maps.emplace_back(absImgName,relPath,false,"",baseName);
303 return static_cast<int>(id);
304}

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

223{
224 std::ifstream f = Portable::openInputStream(mapName);
225 if (!f.is_open())
226 {
227 err("problems opening map file {} for inclusion in the docs!\n"
228 "If you installed Graphviz/dot after a previous failing run, \n"
229 "try deleting the output directory and rerun doxygen.\n",mapName);
230 return FALSE;
231 }
232 std::string line;
233 while (getline(f,line)) // foreach line
234 {
235 QCString buf = line+'\n';
236 if (buf.startsWith("<area"))
237 {
238 QCString replBuf = replaceRef(buf,relPath,urlOnly,context);
239 // in dot version 7.0.2 the alt attribute is, incorrectly, removed.
240 // see https://gitlab.com/graphviz/graphviz/-/issues/265
241 int indexA = replBuf.find("alt=");
242 if (indexA == -1)
243 {
244 replBuf = replBuf.left(5) + " alt=\"\"" + replBuf.right(replBuf.length() - 5);
245 }
246
247 // strip id="..." from replBuf since the id's are not needed and not unique.
248 int indexS = replBuf.find("id=\""), indexE = 0;
249 if (indexS>0 && (indexE=replBuf.find('"',indexS+4))!=-1)
250 {
251 t << replBuf.left(indexS-1) << replBuf.right(replBuf.length() - indexE - 1);
252 }
253 else
254 {
255 t << replBuf;
256 }
257 }
258 }
259 return TRUE;
260}
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 267 of file dotfilepatcher.cpp.

268{
269 return m_patchFile.endsWith(".svg");
270}

References m_patchFile.

Referenced by run().

◆ run()

bool DotFilePatcher::run ( ) const

Definition at line 306 of file dotfilepatcher.cpp.

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

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

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