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.
pull/57/head
Tatsuhiro Tsujikawa 2013-03-03 21:49:42 +09:00
parent e17d0f8d4e
commit 43cb2d880a
2 changed files with 47 additions and 18 deletions

View File

@ -72,6 +72,13 @@ GZipFile::GZipFile(const char* filename, const char* mode)
} }
fclose(fp); fclose(fp);
} }
buflen_ = 1024;
buf_ = reinterpret_cast<char*>(malloc(buflen_));
}
GZipFile::~GZipFile()
{
free(buf_);
} }
int GZipFile::close() int GZipFile::close()
@ -136,26 +143,46 @@ int GZipFile::flush()
int GZipFile::vprintf(const char* format, va_list va) int GZipFile::vprintf(const char* format, va_list va)
{ {
char *buf = 0; ssize_t len;
size_t len; #ifdef __MINGW32__
// Windows vsnprintf returns -1 when output is truncated, so we
int rv = ::vasprintf(&buf, format, va); // cannot use same logic in non-MINGW32 code.
if (rv <= 0) { len = _vscprintf(format, va);
// buf is undefined at this point if(len == 0) {
// do not attempt to free it return 0;
return rv;
} }
// Include terminate null
len = strlen(buf); ++len;
if (len) { if(len > static_cast<ssize_t>(buflen_)) {
rv = gzwrite(fp_, buf, len); while(static_cast<ssize_t>(buflen_) < len) {
buflen_ *= 2;
} }
buf_ = reinterpret_cast<char*>(realloc(buf_, buflen_));
if (buf) {
free(buf);
} }
return rv; len = vsnprintf(buf_, buflen_, format, va);
if(len < 0) {
return len;
}
#else // !__MINGW32__
for(;;) {
len = vsnprintf(buf_, buflen_, format, va);
// len does not include terminating null
if(len >= static_cast<ssize_t>(buflen_)) {
// Include terminate null
++len;
// truncated; reallocate buf and try again
while(static_cast<ssize_t>(buflen_) < len) {
buflen_ *= 2;
}
buf_ = reinterpret_cast<char*>(realloc(buf_, buflen_));
} else if(len < 0) {
return len;
} else {
break;
}
}
#endif // !__MINGW32__
return gzwrite(fp_, buf_, len);
} }
} // namespace aria2 } // namespace aria2

View File

@ -45,7 +45,7 @@ namespace aria2 {
class GZipFile: public BufferedFile { class GZipFile: public BufferedFile {
public: public:
GZipFile(const char* filename, const char* mode); GZipFile(const char* filename, const char* mode);
virtual ~GZipFile() {} virtual ~GZipFile();
virtual int close(); virtual int close();
virtual size_t read(void* ptr, size_t count); virtual size_t read(void* ptr, size_t count);
virtual size_t write(const void* ptr, size_t count); virtual size_t write(const void* ptr, size_t count);
@ -60,6 +60,8 @@ private:
gzFile fp_; gzFile fp_;
bool open_; bool open_;
char* buf_;
size_t buflen_;
protected: protected:
virtual bool isError() const; virtual bool isError() const;
virtual bool isEOF() const { return gzeof(fp_); } virtual bool isEOF() const { return gzeof(fp_); }