Doxygen
Loading...
Searching...
No Matches
DotRunner Class Reference

Helper class to run dot from doxygen from multiple threads. More...

#include <src/dotrunner.h>

Collaboration diagram for DotRunner:

Classes

struct  DotJob

Public Member Functions

 DotRunner (const QCString &absDotName, const QCString &md5Hash=QCString())
 Creates a runner for a dot file.
void addJob (const QCString &format, const QCString &output, const QCString &srcFile, int srcLine)
 Adds an additional job to the run.
void preventCleanUp ()
 Prevent cleanup of the dot file (for user provided dot files).
bool run ()
 Runs dot for all jobs added.
QCString getMd5Hash ()

Static Public Member Functions

static bool readBoundingBox (const QCString &fileName, int *width, int *height, bool isEps)

Private Attributes

QCString m_file
QCString m_md5Hash
QCString m_dotExe
bool m_cleanUp
std::vector< DotJobm_jobs

Detailed Description

Helper class to run dot from doxygen from multiple threads.

Definition at line 30 of file dotrunner.h.

Constructor & Destructor Documentation

◆ DotRunner()

DotRunner::DotRunner ( const QCString & absDotName,
const QCString & md5Hash = QCString() )

Creates a runner for a dot file.

Definition at line 258 of file dotrunner.cpp.

259 : m_file(absDotName)
260 , m_md5Hash(md5Hash)
262 , m_cleanUp(Config_getBool(DOT_CLEANUP))
263{
264}
QCString m_file
Definition dotrunner.h:64
bool m_cleanUp
Definition dotrunner.h:67
QCString m_md5Hash
Definition dotrunner.h:65
QCString m_dotExe
Definition dotrunner.h:66
static QCString verifiedDotPath
Definition doxygen.h:139
#define Config_getBool(name)
Definition config.h:33

References Config_getBool, m_cleanUp, m_dotExe, m_file, and m_md5Hash.

Member Function Documentation

◆ addJob()

void DotRunner::addJob ( const QCString & format,
const QCString & output,
const QCString & srcFile,
int srcLine )

Adds an additional job to the run.

Performing multiple jobs one file can be faster.

Definition at line 267 of file dotrunner.cpp.

269{
270
271 for (auto& s: m_jobs)
272 {
273 if (s.format != format) continue;
274 if (s.output != output) continue;
275 // we have this job already
276 return;
277 }
278 auto args = QCString("-T") + format + " -o \"" + output + "\"";
279 m_jobs.emplace_back(format, output, args, srcFile, srcLine);
280}
std::vector< DotJob > m_jobs
Definition dotrunner.h:68

References m_jobs.

Referenced by DotGraph::prepareDotFile(), writeDotGraphFromFile(), and writeDotImageMapFromFile().

◆ getMd5Hash()

QCString DotRunner::getMd5Hash ( )
inline

Definition at line 59 of file dotrunner.h.

59{ return m_md5Hash; }

References m_md5Hash.

◆ preventCleanUp()

void DotRunner::preventCleanUp ( )
inline

Prevent cleanup of the dot file (for user provided dot files).

Definition at line 54 of file dotrunner.h.

54{ m_cleanUp = false; }

References m_cleanUp.

Referenced by writeDotGraphFromFile(), and writeDotImageMapFromFile().

◆ readBoundingBox()

bool DotRunner::readBoundingBox ( const QCString & fileName,
int * width,
int * height,
bool isEps )
static

Definition at line 138 of file dotrunner.cpp.

139{
140 std::ifstream f = Portable::openInputStream(fileName);
141 if (!f.is_open())
142 {
143 err("Failed to open file {} for extracting bounding box\n",fileName);
144 return false;
145 }
146
147 // read file contents into string 'contents'
148 std::stringstream buffer;
149 buffer << f.rdbuf();
150 std::string contents = buffer.str();
151
152 // start of bounding box marker we are looking for
153 const std::string boundingBox = isEps ? "%%PageBoundingBox:" : "/MediaBox [";
154
155 // helper routine to extract the bounding boxes width and height
156 auto extractBoundingBox = [&fileName,&boundingBox,&width,&height](const char *s) -> bool
157 {
158 int x=0, y=0;
159 double w=0, h=0;
160 if (sscanf(s+boundingBox.length(),"%d %d %lf %lf",&x,&y,&w,&h)==4)
161 {
162 *width = static_cast<int>(std::ceil(w));
163 *height = static_cast<int>(std::ceil(h));
164 return true;
165 }
166 err("Failed to extract bounding box from generated diagram file {}\n",fileName);
167 return false;
168 };
169
170 // compressed segment start and end markers
171 const std::string streamStart = "stream\n";
172 const std::string streamEnd = "\nendstream";
173
174 auto detectDeflateStreamStart = [&streamStart](const char *s)
175 {
176 size_t len = streamStart.length();
177 bool streamOK = strncmp(s,streamStart.c_str(),len)==0;
178 if (streamOK) // ASCII marker matches, check stream header bytes as well
179 {
180 unsigned short header1 = static_cast<unsigned char>(s[len])<<8; // CMF byte
181 if (header1) // not end of string
182 {
183 unsigned short header = (static_cast<unsigned char>(s[len+1])) | header1; // FLG byte
184 // check for correct header (see https://www.rfc-editor.org/rfc/rfc1950)
185 return ((header&0x8F20)==0x0800) && (header%31)==0;
186 }
187 }
188 return false;
189 };
190
191 const size_t l = contents.length();
192 size_t i=0;
193 while (i<l)
194 {
195 if (!isEps && contents[i]=='s' && detectDeflateStreamStart(&contents[i]))
196 { // compressed stream start
197 int col=17;
198 i+=streamStart.length();
199 const size_t start=i;
200 DBG(("---- start stream at offset %08x\n",(int)i));
201 while (i<l)
202 {
203 if (contents[i]=='\n' && strncmp(&contents[i],streamEnd.c_str(),streamEnd.length())==0)
204 { // compressed block found in range [start..i]
205 DBG(("\n---- end stream at offset %08x\n",(int)i));
206 // decompress it into decompressBuf
207 std::vector<char> decompressBuf;
208 const char *source = &contents[start];
209 const size_t sourceLen = i-start;
210 size_t sourcePos = 0;
211 decompressBuf.reserve(sourceLen*2);
212 auto getter = [source,&sourcePos,sourceLen]() -> int {
213 return sourcePos<sourceLen ? static_cast<unsigned char>(source[sourcePos++]) : EOF;
214 };
215 auto putter = [&decompressBuf](const char c) -> int {
216 decompressBuf.push_back(c); return c;
217 };
218 Deflate(getter,putter);
219 // convert decompression buffer to string
220 std::string s(decompressBuf.begin(), decompressBuf.end());
221 DBG(("decompressed_data=[[[\n%s\n]]]\n",s.c_str()));
222 // search for bounding box marker
223 const size_t idx = s.find(boundingBox);
224 if (idx!=std::string::npos) // found bounding box in uncompressed data
225 {
226 return extractBoundingBox(s.c_str()+idx);
227 }
228 // continue searching after end stream marker
229 i+=streamEnd.length();
230 break;
231 }
232 else // compressed stream character
233 {
234 if (col>16) { col=0; DBG(("\n%08x: ",static_cast<int>(i))); }
235 DBG(("%02x ",static_cast<unsigned char>(contents[i])));
236 col++;
237 i++;
238 }
239 }
240 }
241 else if (((isEps && contents[i]=='%') || (!isEps && contents[i]=='/')) &&
242 strncmp(&contents[i],boundingBox.c_str(),boundingBox.length())==0)
243 { // uncompressed bounding box
244 return extractBoundingBox(&contents[i]);
245 }
246 else // uncompressed stream character
247 {
248 i++;
249 }
250 }
251 err("Failed to find bounding box in generated diagram file {}\n",fileName);
252 // nothing found
253 return false;
254}
#define DBG(x)
Definition dotrunner.cpp:63
static bool extractBoundingBox(const QCString &formBase, int *x1, int *y1, int *x2, int *y2, double *x1hi, double *y1hi, double *x2hi, double *y2hi)
Definition formula.cpp:299
#define err(fmt,...)
Definition message.h:127
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:660

References DBG, err, extractBoundingBox(), and Portable::openInputStream().

Referenced by run(), and DotFilePatcher::writeVecGfxFigure().

◆ run()

bool DotRunner::run ( )

Runs dot for all jobs added.

Definition at line 289 of file dotrunner.cpp.

290{
291 int exitCode=0;
292
293 QCString dotArgs;
294
295 QCString srcFile;
296 int srcLine=-1;
297
298 // create output
299 if (Config_getBool(DOT_MULTI_TARGETS))
300 {
301 dotArgs=QCString("\"")+m_file+"\"";
302 for (auto& s: m_jobs)
303 {
304 dotArgs+=' ';
305 dotArgs+=s.args;
306 }
307 if (!m_jobs.empty())
308 {
309 srcFile = m_jobs.front().srcFile;
310 srcLine = m_jobs.front().srcLine;
311 }
312 if ((exitCode=Portable::system(m_dotExe,dotArgs,FALSE))!=0) goto error;
313 }
314 else
315 {
316 for (auto& s : m_jobs)
317 {
318 srcFile = s.srcFile;
319 srcLine = s.srcLine;
320 dotArgs=QCString("\"")+m_file+"\" "+s.args;
321 if ((exitCode=Portable::system(m_dotExe,dotArgs,FALSE))!=0) goto error;
322 }
323 }
324
325 // check output
326 // As there should be only one pdf file be generated, we don't need code for regenerating multiple pdf files in one call
327 for (auto& s : m_jobs)
328 {
329 if (s.format.startsWith("pdf"))
330 {
331 int width=0,height=0;
332 if (!readBoundingBox(s.output,&width,&height,FALSE)) goto error;
333 if ((width > MAX_LATEX_GRAPH_SIZE) || (height > MAX_LATEX_GRAPH_SIZE))
334 {
335 if (!resetPDFSize(width,height,getBaseNameOfOutput(s.output))) goto error;
336 dotArgs=QCString("\"")+m_file+"\" "+s.args;
337 if ((exitCode=Portable::system(m_dotExe,dotArgs,FALSE))!=0) goto error;
338 }
339 }
340
341 if (s.format.startsWith("png"))
342 {
343 checkPngResult(s.output);
344 }
345 }
346
347 // remove .dot files
348 if (m_cleanUp)
349 {
350 //printf("removing dot file %s\n",qPrint(m_file));
352 }
353
354 // create checksum file
355 if (!m_md5Hash.isEmpty())
356 {
357 QCString md5Name = getBaseNameOfOutput(m_file) + ".md5";
358 FILE *f = Portable::fopen(md5Name,"w");
359 if (f)
360 {
361 fwrite(m_md5Hash.data(),1,32,f);
362 fclose(f);
363 }
364 }
365 return TRUE;
366error:
367 err_full(srcFile,srcLine,"Problems running dot: exit code={}, command='{}', arguments='{}'",
368 exitCode,m_dotExe,dotArgs);
369 return FALSE;
370}
static bool readBoundingBox(const QCString &fileName, int *width, int *height, bool isEps)
QCString getBaseNameOfOutput(const QCString &output)
static void checkPngResult(const QCString &imgName)
Definition dotrunner.cpp:69
#define MAX_LATEX_GRAPH_SIZE
Definition dotrunner.cpp:60
static bool resetPDFSize(const int width, const int height, const QCString &base)
Definition dotrunner.cpp:96
#define err_full(file, line, fmt,...)
Definition message.h:132
void unlink(const QCString &fileName)
Definition portable.cpp:545
FILE * fopen(const QCString &fileName, const QCString &mode)
Definition portable.cpp:350
int system(const QCString &command, const QCString &args, bool commandHasConsole=true)
Definition portable.cpp:106
int fclose(FILE *f)
Definition portable.cpp:370
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34

References checkPngResult(), Config_getBool, err_full, FALSE, Portable::fopen(), getBaseNameOfOutput(), m_cleanUp, m_dotExe, m_file, m_jobs, m_md5Hash, MAX_LATEX_GRAPH_SIZE, readBoundingBox(), resetPDFSize(), Portable::system(), TRUE, and Portable::unlink().

Referenced by DotManager::run(), writeDotGraphFromFile(), and writeDotImageMapFromFile().

Member Data Documentation

◆ m_cleanUp

bool DotRunner::m_cleanUp
private

Definition at line 67 of file dotrunner.h.

Referenced by DotRunner(), preventCleanUp(), and run().

◆ m_dotExe

QCString DotRunner::m_dotExe
private

Definition at line 66 of file dotrunner.h.

Referenced by DotRunner(), and run().

◆ m_file

QCString DotRunner::m_file
private

Definition at line 64 of file dotrunner.h.

Referenced by DotRunner(), and run().

◆ m_jobs

std::vector<DotJob> DotRunner::m_jobs
private

Definition at line 68 of file dotrunner.h.

Referenced by addJob(), and run().

◆ m_md5Hash

QCString DotRunner::m_md5Hash
private

Definition at line 65 of file dotrunner.h.

Referenced by DotRunner(), getMd5Hash(), and run().


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