20#pragma warning( push )
21#pragma warning( disable : 4242 )
22#pragma warning( disable : 4244 )
23#pragma warning( disable : 4996 )
26#pragma clang diagnostic push
27#pragma clang diagnostic ignored "-Wdeprecated-declarations"
31#pragma clang diagnostic pop
49#define MAX_LATEX_GRAPH_INCH 150
50#define MAX_LATEX_GRAPH_SIZE (MAX_LATEX_GRAPH_INCH * 72)
53#define DBG(x) do {} while(0)
65 if (fread(data,1,4,f)==4)
67 if (!(data[1]==
'P' && data[2]==
'N' && data[3]==
'G'))
69 err(
"Image '%s' produced by dot is not a valid PNG!\n"
70 "You should either select a different format "
71 "(DOT_IMAGE_FORMAT in the config file) or install a more "
72 "recent version of graphviz (1.7+)\n",
qPrint(imgName)
78 err(
"Could not read image '%s' generated by dot!\n",
qPrint(imgName));
84 err(
"Could not open image '%s' generated by dot!\n",
qPrint(imgName));
95 err(
"Failed to rename file %s to %s!\n",
qPrint(patchFile),
qPrint(tmpName));
102 err(
"problem opening file %s for patching!\n",
qPrint(tmpName));
108 err(
"problem opening file %s for patching!\n",
qPrint(patchFile));
113 while (getline(fi,line))
115 if (line.find(
"LATEX_PDF_SIZE") != std::string::npos)
118 t <<
" size=\""<<width/scale <<
"," <<height/scale <<
"\";\n";
135 err(
"Failed to open file %s for extracting bounding box\n",
qPrint(fileName));
140 std::stringstream buffer;
142 std::string contents = buffer.str();
145 const std::string boundingBox = isEps ?
"%%PageBoundingBox:" :
"/MediaBox [";
148 auto extractBoundingBox = [&fileName,&boundingBox,&width,&height](
const char *s) ->
bool
152 if (sscanf(s+boundingBox.length(),
"%d %d %lf %lf",&x,&y,&w,&h)==4)
154 *width =
static_cast<int>(std::ceil(w));
155 *height =
static_cast<int>(std::ceil(h));
158 err(
"Failed to extract bounding box from generated diagram file %s\n",
qPrint(fileName));
163 const std::string streamStart =
"stream\n";
164 const std::string streamEnd =
"\nendstream";
166 auto detectDeflateStreamStart = [&streamStart](
const char *s)
168 size_t len = streamStart.length();
169 bool streamOK = strncmp(s,streamStart.c_str(),len)==0;
172 unsigned short header1 =
static_cast<unsigned char>(s[len])<<8;
175 unsigned short header = (
static_cast<unsigned char>(s[len+1])) | header1;
177 return ((header&0x8F20)==0x0800) && (header%31)==0;
183 const size_t l = contents.length();
187 if (!isEps && contents[i]==
's' && detectDeflateStreamStart(&contents[i]))
190 i+=streamStart.length();
191 const size_t start=i;
192 DBG((
"---- start stream at offset %08x\n",(
int)i));
195 if (contents[i]==
'\n' && strncmp(&contents[i],streamEnd.c_str(),streamEnd.length())==0)
197 DBG((
"\n---- end stream at offset %08x\n",(
int)i));
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;
207 auto putter = [&decompressBuf](
const char c) ->
int {
208 decompressBuf.push_back(c);
return c;
210 Deflate(getter,putter);
212 std::string s(decompressBuf.begin(), decompressBuf.end());
213 DBG((
"decompressed_data=[[[\n%s\n]]]\n",s.c_str()));
215 const size_t idx = s.find(boundingBox);
216 if (idx!=std::string::npos)
221 i+=streamEnd.length();
226 if (col>16) { col=0;
DBG((
"\n%08x: ",
static_cast<int>(i))); }
227 DBG((
"%02x ",
static_cast<unsigned char>(contents[i])));
233 else if (((isEps && contents[i]==
'%') || (!isEps && contents[i]==
'/')) &&
234 strncmp(&contents[i],boundingBox.c_str(),boundingBox.length())==0)
243 err(
"Failed to find bounding box in generated diagram file %s\n",
qPrint(fileName));
260 const QCString &srcFile,
int srcLine)
265 if (s.format != format)
continue;
266 if (s.output != output)
continue;
270 auto args =
QCString(
"-T") + format +
" -o \"" + output +
"\"";
271 m_jobs.emplace_back(format, output, args, srcFile, srcLine);
276 int index = output.
findRev(
'.');
277 if (index < 0)
return output;
278 return output.
left(index);
301 srcFile =
m_jobs.front().srcFile;
302 srcLine =
m_jobs.front().srcLine;
321 if (s.format.startsWith(
"pdf"))
323 int width=0,height=0;
333 if (s.format.startsWith(
"png"))
359 err_full(srcFile,srcLine,
"Problems running dot: exit code=%d, command='%s', arguments='%s'",
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.
const char * qPrint(const char *s)
A bunch of utility functions.