20#pragma warning( push )
21#pragma warning( disable : 4242 )
22#pragma warning( disable : 4244 )
23#pragma warning( disable : 4996 )
24#pragma warning( disable : 4456 )
25#pragma warning( disable : 4805 )
28#pragma clang diagnostic push
29#pragma clang diagnostic ignored "-Wdeprecated-declarations"
30#pragma clang diagnostic ignored "-Wshadow"
33#pragma GCC diagnostic push
34#pragma GCC diagnostic ignored "-Wshadow"
38#pragma GCC diagnostic pop
41#pragma clang diagnostic pop
59#define MAX_LATEX_GRAPH_INCH 150
60#define MAX_LATEX_GRAPH_SIZE (MAX_LATEX_GRAPH_INCH * 72)
63#define DBG(x) do {} while(0)
74 err(
"Could not read image '{}' generated by dot!\n",imgName);
79 if (fread(data, 1, 4, f) != 4)
81 err(
"Could not read image '{}' generated by dot!\n",imgName);
86 if (!(data[1] ==
'P' && data[2] ==
'N' && data[3] ==
'G'))
88 err(
"Image '{}' produced by dot is not a valid PNG!\n"
89 "You should either select a different format "
90 "(DOT_IMAGE_FORMAT in the config file) or install a more "
91 "recent version of graphviz (1.7+)\n", imgName);
104 err(
"Failed to rename file {} to {}!\n",patchFile,tmpName);
111 err(
"problem opening file {} for patching!\n",tmpName);
117 err(
"problem opening file {} for patching!\n",patchFile);
122 while (getline(fi,line))
124 if (line.find(
"LATEX_PDF_SIZE") != std::string::npos)
127 t <<
" size=\""<<width/scale <<
"," <<height/scale <<
"\";\n";
144 err(
"Failed to open file {} for extracting bounding box\n",fileName);
149 std::stringstream buffer;
151 std::string contents = buffer.str();
154 const std::string boundingBox = isEps ?
"%%PageBoundingBox:" :
"/MediaBox [";
157 auto extractBoundingBox = [&fileName,&boundingBox,&width,&height](
const char *s) ->
bool
161 if (sscanf(s+boundingBox.length(),
"%d %d %lf %lf",&x,&y,&w,&h)==4)
163 *width =
static_cast<int>(std::ceil(w));
164 *height =
static_cast<int>(std::ceil(h));
167 err(
"Failed to extract bounding box from generated diagram file {}\n",fileName);
172 const std::string streamStart =
"stream\n";
173 const std::string streamEnd =
"\nendstream";
175 auto detectDeflateStreamStart = [&streamStart](
const char *s)
177 size_t len = streamStart.length();
178 bool streamOK = strncmp(s,streamStart.c_str(),len)==0;
181 unsigned short header1 =
static_cast<unsigned char>(s[len])<<8;
184 unsigned short header = (
static_cast<unsigned char>(s[len+1])) | header1;
186 return ((header&0x8F20)==0x0800) && (header%31)==0;
192 const size_t l = contents.length();
196 if (!isEps && contents[i]==
's' && detectDeflateStreamStart(&contents[i]))
199 i+=streamStart.length();
200 const size_t start=i;
201 DBG((
"---- start stream at offset %08x\n",(
int)i));
204 if (contents[i]==
'\n' && strncmp(&contents[i],streamEnd.c_str(),streamEnd.length())==0)
206 DBG((
"\n---- end stream at offset %08x\n",(
int)i));
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;
216 auto putter = [&decompressBuf](
const char c) ->
int {
217 decompressBuf.push_back(c);
return c;
219 Deflate(getter,putter);
221 std::string s(decompressBuf.begin(), decompressBuf.end());
222 DBG((
"decompressed_data=[[[\n%s\n]]]\n",s.c_str()));
224 const size_t idx = s.find(boundingBox);
225 if (idx!=std::string::npos)
230 i+=streamEnd.length();
235 if (col>16) { col=0;
DBG((
"\n%08x: ",
static_cast<int>(i))); }
236 DBG((
"%02x ",
static_cast<unsigned char>(contents[i])));
242 else if (((isEps && contents[i]==
'%') || (!isEps && contents[i]==
'/')) &&
243 strncmp(&contents[i],boundingBox.c_str(),boundingBox.length())==0)
252 err(
"Failed to find bounding box in generated diagram file {}\n",fileName);
269 const QCString &srcFile,
int srcLine)
274 if (s.format != format)
continue;
275 if (s.output != output)
continue;
279 auto args =
QCString(
"-T") + format +
" -o \"" + output +
"\"";
280 m_jobs.emplace_back(format, output, args, srcFile, srcLine);
285 int index = output.
findRev(
'.');
286 if (index < 0)
return output;
287 return output.
left(index);
310 srcFile =
m_jobs.front().srcFile;
311 srcLine =
m_jobs.front().srcLine;
330 if (s.format.startsWith(
"pdf"))
332 int width=0,height=0;
342 if (s.format.startsWith(
"png"))
368 err_full(srcFile,srcLine,
"Problems running dot: exit code={}, command='{}', arguments='{}'",
Class representing a directory in the file system.
bool remove(const std::string &path, bool acceptsAbsPath=true) const
bool rename(const std::string &orgName, const std::string &newName, bool acceptsAbsPath=true) const
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.
bool run()
Runs dot for all jobs added.
std::vector< DotJob > m_jobs
static bool readBoundingBox(const QCString &fileName, int *width, int *height, bool isEps)
This class serves as a namespace for global variables used by doxygen.
This is an alternative implementation of QCString.
const std::string & str() const
int findRev(char c, int index=-1, bool cs=TRUE) const
QCString left(size_t len) const
#define Config_getBool(name)
#define MAX_LATEX_GRAPH_INCH
QCString getBaseNameOfOutput(const QCString &output)
static void checkPngResult(const QCString &imgName)
#define MAX_LATEX_GRAPH_SIZE
static bool resetPDFSize(const int width, const int height, const QCString &base)
#define err_full(file, line, fmt,...)
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
std::ofstream openOutputStream(const QCString &name, bool append=false)
void unlink(const QCString &fileName)
FILE * fopen(const QCString &fileName, const QCString &mode)
int system(const QCString &command, const QCString &args, bool commandHasConsole=true)
Portable versions of functions that are platform dependent.
A bunch of utility functions.