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);
85 if (!(data[1] ==
'P' && data[2] ==
'N' && data[3] ==
'G'))
87 err(
"Image '{}' produced by dot is not a valid PNG!\n"
88 "You should either select a different format "
89 "(DOT_IMAGE_FORMAT in the config file) or install a more "
90 "recent version of graphviz (1.7+)\n", imgName);
103 err(
"Failed to rename file {} to {}!\n",patchFile,tmpName);
110 err(
"problem opening file {} for patching!\n",tmpName);
116 err(
"problem opening file {} for patching!\n",patchFile);
121 while (getline(fi,line))
123 if (line.find(
"LATEX_PDF_SIZE") != std::string::npos)
126 t <<
" size=\""<<width/scale <<
"," <<height/scale <<
"\";\n";
143 err(
"Failed to open file {} for extracting bounding box\n",fileName);
148 std::stringstream buffer;
150 std::string contents = buffer.str();
153 const std::string boundingBox = isEps ?
"%%PageBoundingBox:" :
"/MediaBox [";
156 auto extractBoundingBox = [&fileName,&boundingBox,&width,&height](
const char *s) ->
bool
160 if (sscanf(s+boundingBox.length(),
"%d %d %lf %lf",&x,&y,&w,&h)==4)
162 *width =
static_cast<int>(std::ceil(w));
163 *height =
static_cast<int>(std::ceil(h));
166 err(
"Failed to extract bounding box from generated diagram file {}\n",fileName);
171 const std::string streamStart =
"stream\n";
172 const std::string streamEnd =
"\nendstream";
174 auto detectDeflateStreamStart = [&streamStart](
const char *s)
176 size_t len = streamStart.length();
177 bool streamOK = strncmp(s,streamStart.c_str(),len)==0;
180 unsigned short header1 =
static_cast<unsigned char>(s[len])<<8;
183 unsigned short header = (
static_cast<unsigned char>(s[len+1])) | header1;
185 return ((header&0x8F20)==0x0800) && (header%31)==0;
191 const size_t l = contents.length();
195 if (!isEps && contents[i]==
's' && detectDeflateStreamStart(&contents[i]))
198 i+=streamStart.length();
199 const size_t start=i;
200 DBG((
"---- start stream at offset %08x\n",(
int)i));
203 if (contents[i]==
'\n' && strncmp(&contents[i],streamEnd.c_str(),streamEnd.length())==0)
205 DBG((
"\n---- end stream at offset %08x\n",(
int)i));
207 std::vector<char> decompressBuf;
208 const char *source = &contents[start];
209 const size_t sourceLen = i-start;
210 size_t sourcePos = 0;
211 decompressBuf.reserve(sourceLen*2);
212 auto getter = [source,&sourcePos,sourceLen]() ->
int {
213 return sourcePos<sourceLen ? static_cast<unsigned char>(source[sourcePos++]) : EOF;
215 auto putter = [&decompressBuf](
const char c) ->
int {
216 decompressBuf.push_back(c);
return c;
218 Deflate(getter,putter);
220 std::string s(decompressBuf.begin(), decompressBuf.end());
221 DBG((
"decompressed_data=[[[\n%s\n]]]\n",s.c_str()));
223 const size_t idx = s.find(boundingBox);
224 if (idx!=std::string::npos)
229 i+=streamEnd.length();
234 if (col>16) { col=0;
DBG((
"\n%08x: ",
static_cast<int>(i))); }
235 DBG((
"%02x ",
static_cast<unsigned char>(contents[i])));
241 else if (((isEps && contents[i]==
'%') || (!isEps && contents[i]==
'/')) &&
242 strncmp(&contents[i],boundingBox.c_str(),boundingBox.length())==0)
251 err(
"Failed to find bounding box in generated diagram file {}\n",fileName);
268 const QCString &srcFile,
int srcLine)
273 if (s.format != format)
continue;
274 if (s.output != output)
continue;
278 auto args =
QCString(
"-T") + format +
" -o \"" + output +
"\"";
279 m_jobs.emplace_back(format, output, args, srcFile, srcLine);
284 int index = output.
findRev(
'.');
285 if (index < 0)
return output;
286 return output.
left(index);
309 srcFile =
m_jobs.front().srcFile;
310 srcLine =
m_jobs.front().srcLine;
329 if (s.format.startsWith(
"pdf"))
331 int width=0,height=0;
341 if (s.format.startsWith(
"png"))
367 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.