Skip to main content

The DotFilePatcher Class Reference

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

Declaration

class DotFilePatcher { ... }

Included Headers

Public Constructors Index

DotFilePatcher (const QCString &patchFile)

Public Member Functions Index

intaddMap (const QCString &mapFile, const QCString &relPath, bool urlOnly, const QCString &context, const QCString &label)
intaddFigure (const QCString &baseName, const QCString &figureName, bool heightCheck)
intaddSVGConversion (const QCString &relPath, bool urlOnly, const QCString &context, bool zoomable, int graphId)
intaddSVGObject (const QCString &baseName, const QCString &figureName, const QCString &relPath)
boolrun () const
boolisSVGFile () const

Private Member Attributes Index

std::vector< Map >m_maps
QCStringm_patchFile

Public Static Functions Index

static boolconvertMapFile (TextStream &t, const QCString &mapName, const QCString &relPath, bool urlOnly=FALSE, const QCString &context=QCString())
static boolwriteSVGFigureLink (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. More...

static boolwriteVecGfxFigure (TextStream &out, const QCString &baseName, const QCString &figureName)

Description

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

Definition at line 26 of file dotfilepatcher.h.

Public Constructors

DotFilePatcher()

DotFilePatcher::DotFilePatcher (const QCString & patchFile)

Declaration at line 29 of file dotfilepatcher.h, definition at line 262 of file dotfilepatcher.cpp.

263 : m_patchFile(patchFile)
264{
265}

Reference m_patchFile.

Public Member Functions

addFigure()

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

Declaration at line 33 of file dotfilepatcher.h, definition at line 280 of file dotfilepatcher.cpp.

281 const QCString &figureName,bool heightCheck)
282{
283 size_t id = m_maps.size();
284 m_maps.emplace_back(figureName,"",heightCheck,"",baseName);
285 return static_cast<int>(id);
286}

Reference m_maps.

addMap()

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

Declaration at line 30 of file dotfilepatcher.h, definition at line 272 of file dotfilepatcher.cpp.

272int DotFilePatcher::addMap(const QCString &mapFile,const QCString &relPath,
273 bool urlOnly,const QCString &context,const QCString &label)
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}

Reference m_maps.

addSVGConversion()

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

Declaration at line 36 of file dotfilepatcher.h, definition at line 288 of file dotfilepatcher.cpp.

288int DotFilePatcher::addSVGConversion(const QCString &relPath,bool urlOnly,
289 const QCString &context,bool zoomable,
290 int graphId)
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}

Reference m_maps.

Referenced by writeDotImageMapFromFile.

addSVGObject()

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

Declaration at line 39 of file dotfilepatcher.h, definition at line 297 of file dotfilepatcher.cpp.

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

Reference m_maps.

isSVGFile()

bool DotFilePatcher::isSVGFile ()

Declaration at line 42 of file dotfilepatcher.h, definition at line 267 of file dotfilepatcher.cpp.

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

Reference m_patchFile.

Referenced by run.

run()

bool DotFilePatcher::run ()

Declaration at line 41 of file dotfilepatcher.h, 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 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 if (useNagivation)
388 {
389 t << "<script type=\"application/ecmascript\">\n";
390 t << "var viewWidth = " << width << ";\n";
391 t << "var viewHeight = " << height << ";\n";
392 if (graphId>=0)
393 {
394 t << "var sectionId = 'dynsection-" << graphId << "';\n";
395 }
396 t << "</script>\n";
397 }
398 t << "<script type=\"application/ecmascript\" xlink:href=\"" << relPath << "svg.min.js\"/>\n";
399 t << "<svg id=\"graph\" class=\"graph\">\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")!=-1 && (i=findIndex(line.str(),reSVG))!=-1)
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 int e = std::max(line.find("--]"),line.find("-->"));
431 const Map &map = m_maps.at(mapId);
432 //printf("DotFilePatcher::writeSVGFigure: file=%s zoomable=%d\n",
433 // qPrint(m_patchFile),map.zoomable);
434 if (!writeSVGFigureLink(t,map.relPath,map.label,map.mapFile))
435 {
436 err("Problem extracting size from SVG file {}\n",map.mapFile);
437 }
438 if (e!=-1) t << line.mid(e+3);
439 }
440 else // error invalid map id!
441 {
442 err("Found invalid SVG id in file {}!\n",m_patchFile);
443 t << line.mid(i);
444 }
445 }
446 else if (line.find("MAP")!=-1 && (i=findIndex(line.str(),reMAP))!=-1)
447 {
448 int mapId=-1;
449 t << line.left(i);
450 int n = sscanf(line.data()+i,"<!-- MAP %d",&mapId);
451 if (n==1 && mapId>=0 && mapId<static_cast<int>(m_maps.size()))
452 {
453 TextStream tt;
454 const Map &map = m_maps.at(mapId);
455 //printf("patching MAP %d in file %s with contents of %s\n",
456 // mapId,qPrint(m_patchFile),qPrint(map.mapFile));
457 convertMapFile(tt,map.mapFile,map.relPath,map.urlOnly,map.context);
458 if (!tt.empty())
459 {
460 t << "<map name=\"" << correctId(map.label) << "\" id=\"" << correctId(map.label) << "\">\n";
461 t << tt.str();
462 t << "</map>\n";
463 }
464 }
465 else // error invalid map id!
466 {
467 err("Found invalid MAP id in file {}!\n",m_patchFile);
468 t << line.mid(i);
469 }
470 }
471 else if (line.find("FIG")!=-1 && (i=findIndex(line.str(),reFIG))!=-1)
472 {
473 int mapId=-1;
474 int n = sscanf(line.data()+i+2,"FIG %d",&mapId);
475 //printf("line='%s' n=%d\n",qPrint(line)+i,n);
476 if (n==1 && mapId>=0 && mapId<static_cast<int>(m_maps.size()))
477 {
478 const Map &map = m_maps.at(mapId);
479 //printf("patching FIG %d in file %s with contents of %s\n",
480 // mapId,qPrint(m_patchFile),qPrint(map.mapFile));
481 if (!writeVecGfxFigure(t,map.label,map.mapFile))
482 {
483 err("problem writing FIG {} figure!\n",mapId);
484 return FALSE;
485 }
486 }
487 else // error invalid map id!
488 {
489 err("Found invalid bounding FIG {} in file {}!\n",mapId,m_patchFile);
490 t << line;
491 }
492 }
493 else
494 {
495 t << line;
496 }
497 }
498 if (isSVGFile && interactiveSVG && !useNagivation) t << "</svg>\n";
499
500 fi.close();
501 if (isSVGFile && interactiveSVG && replacedHeader)
502 {
503 QCString orgName=m_patchFile.left(m_patchFile.length()-4)+"_org.svg";
504 if (useNagivation)
505 {
506 t << substitute(svgZoomFooter1,"$orgname",stripPath(orgName));
507 }
508 t << svgZoomFooter2;
509 t.flush();
510 fo.close();
511 // keep original SVG file so we can refer to it, we do need to replace
512 // dummy link by real ones
513 fi = Portable::openInputStream(tmpName);
514 fo = Portable::openOutputStream(orgName);
515 if (!fi.is_open())
516 {
517 err("problem opening file {} for reading!\n",tmpName);
518 return FALSE;
519 }
520 if (!fo.is_open())
521 {
522 err("problem opening file {} for writing!\n",orgName);
523 return FALSE;
524 }
525 t.setStream(&fo);
526 while (getline(fi,lineStr)) // foreach line
527 {
528 std::string line = lineStr+'\n';
529 const Map &map = m_maps.front(); // there is only one 'map' for a SVG file
530 t << replaceRef(line.c_str(),map.relPath,map.urlOnly,map.context,"_top");
531 }
532 t.flush();
533 fi.close();
534 fo.close();
535 }
536 // remove temporary file
537 thisDir.remove(tmpName.str());
538 return TRUE;
539}

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.

Private Member Attributes

m_maps

std::vector<Map> DotFilePatcher::m_maps

Definition at line 69 of file dotfilepatcher.h.

69 std::vector<Map> m_maps;

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

m_patchFile

QCString DotFilePatcher::m_patchFile

Definition at line 70 of file dotfilepatcher.h.

Referenced by DotFilePatcher, isSVGFile and run.

Public Static Functions

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
t

the stream to which the result is written.

mapName

the name of the map file.

relPath

the relative path to the root of the output directory (used in case CREATE_SUBDIRS is enabled).

urlOnly

if FALSE the url field in the map contains an external references followed by a $ and then the URL.

context

the context (file, class, or namespace) in which the map file was found

Returns

TRUE if successful.

Declaration at line 44 of file dotfilepatcher.h, definition at line 220 of file dotfilepatcher.cpp.

221 const QCString &relPath, bool urlOnly,
222 const QCString &context)
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}

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

Referenced by insertMapFile, run and 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).

Declaration at line 48 of file dotfilepatcher.h, definition at line 582 of file dotfilepatcher.cpp.

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

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

Declaration at line 51 of file dotfilepatcher.h, definition at line 621 of file dotfilepatcher.cpp.

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

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

Referenced by DotGraph::generateCode and run.


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


Generated via doxygen2docusaurus by Doxygen 1.14.0.