Skip to main content

The DotRunner Class Reference

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

Declaration

class DotRunner { ... }

Included Headers

#include <src/dotrunner.h>

Public Constructors Index

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

Creates a runner for a dot file. More...

Public Member Functions Index

voidaddJob (const QCString &format, const QCString &output, const QCString &srcFile, int srcLine)

Adds an additional job to the run. More...

voidpreventCleanUp ()

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

boolrun ()

Runs dot for all jobs added. More...

QCStringgetMd5Hash ()

Private Member Attributes Index

QCStringm_file
QCStringm_md5Hash
QCStringm_dotExe
boolm_cleanUp
std::vector< DotJob >m_jobs

Public Static Functions Index

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

Description

Helper class to run dot from doxygen from multiple threads.

Definition at line 30 of file dotrunner.h.

Public Constructors

DotRunner()

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

Creates a runner for a dot file.

Declaration at line 46 of file dotrunner.h, definition at line 260 of file dotrunner.cpp.

260DotRunner::DotRunner(const QCString& absDotName, const QCString& md5Hash)
261 : m_file(absDotName)
262 , m_md5Hash(md5Hash)
263 , m_dotExe(Doxygen::verifiedDotPath)
264 , m_cleanUp(Config_getBool(DOT_CLEANUP))
265{
266}

References Config_getBool, m_cleanUp, m_dotExe, m_file and m_md5Hash.

Public Member Functions

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.

Declaration at line 51 of file dotrunner.h, definition at line 269 of file dotrunner.cpp.

269void DotRunner::addJob(const QCString &format, const QCString &output,
270 const QCString &srcFile,int srcLine)
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}

Reference m_jobs.

Referenced by DotGraph::prepareDotFile, writeDotGraphFromFile and writeDotImageMapFromFile.

getMd5Hash()

QCString DotRunner::getMd5Hash ()
inline

Definition at line 59 of file dotrunner.h.

Reference 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 void preventCleanUp() { m_cleanUp = false; }

Reference m_cleanUp.

Referenced by writeDotGraphFromFile and writeDotImageMapFromFile.

run()

bool DotRunner::run ()

Runs dot for all jobs added.

Declaration at line 57 of file dotrunner.h, 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}

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.

Private Member Attributes

m_cleanUp

bool DotRunner::m_cleanUp

Definition at line 67 of file dotrunner.h.

Referenced by DotRunner, preventCleanUp and run.

m_dotExe

QCString DotRunner::m_dotExe

Definition at line 66 of file dotrunner.h.

Referenced by DotRunner and run.

m_file

QCString DotRunner::m_file

Definition at line 64 of file dotrunner.h.

Referenced by DotRunner and run.

m_jobs

std::vector<DotJob> DotRunner::m_jobs

Definition at line 68 of file dotrunner.h.

68 std::vector<DotJob> m_jobs;

Referenced by addJob and run.

m_md5Hash

QCString DotRunner::m_md5Hash

Definition at line 65 of file dotrunner.h.

Referenced by DotRunner, getMd5Hash and run.

Public Static Functions

readBoundingBox()

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

Declaration at line 61 of file dotrunner.h, definition at line 140 of file dotrunner.cpp.

140bool DotRunner::readBoundingBox(const QCString &fileName,int *width,int *height,bool isEps)
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}

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

Referenced by run and DotFilePatcher::writeVecGfxFigure.


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


Generated via doxygen2docusaurus by Doxygen 1.14.0.