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

251 : m_file(absDotName)
252 , m_md5Hash(md5Hash)
254 , m_cleanUp(Config_getBool(DOT_CLEANUP))
255{
256}
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 259 of file dotrunner.cpp.

261{
262
263 for (auto& s: m_jobs)
264 {
265 if (s.format != format) continue;
266 if (s.output != output) continue;
267 // we have this job already
268 return;
269 }
270 auto args = QCString("-T") + format + " -o \"" + output + "\"";
271 m_jobs.emplace_back(format, output, args, srcFile, srcLine);
272}
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 130 of file dotrunner.cpp.

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

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

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

◆ run()

bool DotRunner::run ( )

Runs dot for all jobs added.

Definition at line 281 of file dotrunner.cpp.

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