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)
75 if (fread(data,1,4,f)==4)
77 if (!(data[1]==
'P' && data[2]==
'N' && data[3]==
'G'))
79 err(
"Image '{}' produced by dot is not a valid PNG!\n"
80 "You should either select a different format "
81 "(DOT_IMAGE_FORMAT in the config file) or install a more "
82 "recent version of graphviz (1.7+)\n",imgName
88 err(
"Could not read image '{}' generated by dot!\n",imgName);
94 err(
"Could not open image '{}' generated by dot!\n",imgName);
105 err(
"Failed to rename file {} to {}!\n",patchFile,tmpName);
112 err(
"problem opening file {} for patching!\n",tmpName);
118 err(
"problem opening file {} for patching!\n",patchFile);
123 while (getline(fi,line))
125 if (line.find(
"LATEX_PDF_SIZE") != std::string::npos)
128 t <<
" size=\""<<width/scale <<
"," <<height/scale <<
"\";\n";
145 err(
"Failed to open file {} for extracting bounding box\n",fileName);
150 std::stringstream buffer;
152 std::string contents = buffer.str();
155 const std::string boundingBox = isEps ?
"%%PageBoundingBox:" :
"/MediaBox [";
158 auto extractBoundingBox = [&fileName,&boundingBox,&width,&height](
const char *s) ->
bool
162 if (sscanf(s+boundingBox.length(),
"%d %d %lf %lf",&x,&y,&w,&h)==4)
164 *width =
static_cast<int>(std::ceil(w));
165 *height =
static_cast<int>(std::ceil(h));
168 err(
"Failed to extract bounding box from generated diagram file {}\n",fileName);
173 const std::string streamStart =
"stream\n";
174 const std::string streamEnd =
"\nendstream";
176 auto detectDeflateStreamStart = [&streamStart](
const char *s)
178 size_t len = streamStart.length();
179 bool streamOK = strncmp(s,streamStart.c_str(),len)==0;
182 unsigned short header1 =
static_cast<unsigned char>(s[len])<<8;
185 unsigned short header = (
static_cast<unsigned char>(s[len+1])) | header1;
187 return ((header&0x8F20)==0x0800) && (header%31)==0;
193 const size_t l = contents.length();
197 if (!isEps && contents[i]==
's' && detectDeflateStreamStart(&contents[i]))
200 i+=streamStart.length();
201 const size_t start=i;
202 DBG((
"---- start stream at offset %08x\n",(
int)i));
205 if (contents[i]==
'\n' && strncmp(&contents[i],streamEnd.c_str(),streamEnd.length())==0)
207 DBG((
"\n---- end stream at offset %08x\n",(
int)i));
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;
217 auto putter = [&decompressBuf](
const char c) ->
int {
218 decompressBuf.push_back(c);
return c;
220 Deflate(getter,putter);
222 std::string s(decompressBuf.begin(), decompressBuf.end());
223 DBG((
"decompressed_data=[[[\n%s\n]]]\n",s.c_str()));
225 const size_t idx = s.find(boundingBox);
226 if (idx!=std::string::npos)
231 i+=streamEnd.length();
236 if (col>16) { col=0;
DBG((
"\n%08x: ",
static_cast<int>(i))); }
237 DBG((
"%02x ",
static_cast<unsigned char>(contents[i])));
243 else if (((isEps && contents[i]==
'%') || (!isEps && contents[i]==
'/')) &&
244 strncmp(&contents[i],boundingBox.c_str(),boundingBox.length())==0)
253 err(
"Failed to find bounding box in generated diagram file {}\n",fileName);
270 const QCString &srcFile,
int srcLine)
275 if (s.format != format)
continue;
276 if (s.output != output)
continue;
280 auto args =
QCString(
"-T") + format +
" -o \"" + output +
"\"";
281 m_jobs.emplace_back(format, output, args, srcFile, srcLine);
286 int index = output.
findRev(
'.');
287 if (index < 0)
return output;
288 return output.
left(index);
311 srcFile =
m_jobs.front().srcFile;
312 srcLine =
m_jobs.front().srcLine;
331 if (s.format.startsWith(
"pdf"))
333 int width=0,height=0;
343 if (s.format.startsWith(
"png"))
369 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.