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

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

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

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

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

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