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 259 of file dotrunner.cpp.

260 : m_file(absDotName)
261 , m_md5Hash(md5Hash)
263 , m_cleanUp(Config_getBool(DOT_CLEANUP))
264{
265}
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 268 of file dotrunner.cpp.

270{
271
272 for (auto& s: m_jobs)
273 {
274 if (s.format != format) continue;
275 if (s.output != output) continue;
276 // we have this job already
277 return;
278 }
279 auto args = QCString("-T") + format + " -o \"" + output + "\"";
280 m_jobs.emplace_back(format, output, args, srcFile, srcLine);
281}
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 139 of file dotrunner.cpp.

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

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