From 43cb2d880aea545ccd10c0c4366013f16437828c Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 3 Mar 2013 21:49:42 +0900 Subject: [PATCH] Rewrite GZipFile::vprintf() MINGW does not have vasprintf(), so we use _vscprintf() and vsnprintf(). We want to reuse buffer, so for non-MINGW we use vsnprintf() with retrying doubling buffer size if output is truncated. --- src/GZipFile.cc | 61 +++++++++++++++++++++++++++++++++++-------------- src/GZipFile.h | 4 +++- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/GZipFile.cc b/src/GZipFile.cc index 8acb1bd9..d386d60b 100644 --- a/src/GZipFile.cc +++ b/src/GZipFile.cc @@ -72,6 +72,13 @@ GZipFile::GZipFile(const char* filename, const char* mode) } fclose(fp); } + buflen_ = 1024; + buf_ = reinterpret_cast(malloc(buflen_)); +} + +GZipFile::~GZipFile() +{ + free(buf_); } int GZipFile::close() @@ -136,26 +143,46 @@ int GZipFile::flush() int GZipFile::vprintf(const char* format, va_list va) { - char *buf = 0; - size_t len; - - int rv = ::vasprintf(&buf, format, va); - if (rv <= 0) { - // buf is undefined at this point - // do not attempt to free it - return rv; + ssize_t len; +#ifdef __MINGW32__ + // Windows vsnprintf returns -1 when output is truncated, so we + // cannot use same logic in non-MINGW32 code. + len = _vscprintf(format, va); + if(len == 0) { + return 0; } - - len = strlen(buf); - if (len) { - rv = gzwrite(fp_, buf, len); + // Include terminate null + ++len; + if(len > static_cast(buflen_)) { + while(static_cast(buflen_) < len) { + buflen_ *= 2; + } + buf_ = reinterpret_cast(realloc(buf_, buflen_)); } - - if (buf) { - free(buf); + len = vsnprintf(buf_, buflen_, format, va); + if(len < 0) { + return len; } - return rv; +#else // !__MINGW32__ + for(;;) { + len = vsnprintf(buf_, buflen_, format, va); + // len does not include terminating null + if(len >= static_cast(buflen_)) { + // Include terminate null + ++len; + // truncated; reallocate buf and try again + while(static_cast(buflen_) < len) { + buflen_ *= 2; + } + buf_ = reinterpret_cast(realloc(buf_, buflen_)); + } else if(len < 0) { + return len; + } else { + break; + } + } +#endif // !__MINGW32__ + return gzwrite(fp_, buf_, len); } - } // namespace aria2 diff --git a/src/GZipFile.h b/src/GZipFile.h index a447dccc..9e294235 100644 --- a/src/GZipFile.h +++ b/src/GZipFile.h @@ -45,7 +45,7 @@ namespace aria2 { class GZipFile: public BufferedFile { public: GZipFile(const char* filename, const char* mode); - virtual ~GZipFile() {} + virtual ~GZipFile(); virtual int close(); virtual size_t read(void* ptr, size_t count); virtual size_t write(const void* ptr, size_t count); @@ -60,6 +60,8 @@ private: gzFile fp_; bool open_; + char* buf_; + size_t buflen_; protected: virtual bool isError() const; virtual bool isEOF() const { return gzeof(fp_); }