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

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

References m_patchFile.

Member Function Documentation

◆ addFigure()

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

Definition at line 279 of file dotfilepatcher.cpp.

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

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

References m_maps.

◆ addSVGConversion()

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

Definition at line 287 of file dotfilepatcher.cpp.

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

References m_maps.

Referenced by writeDotImageMapFromFile().

◆ addSVGObject()

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

Definition at line 296 of file dotfilepatcher.cpp.

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

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

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

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

References m_patchFile.

Referenced by run().

◆ run()

bool DotFilePatcher::run ( ) const

Definition at line 305 of file dotfilepatcher.cpp.

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

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

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

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