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);
}
buflen_ = 1024;
buf_ = reinterpret_cast<char*>(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<ssize_t>(buflen_)) {
while(static_cast<ssize_t>(buflen_) < len) {
buflen_ *= 2;
}
buf_ = reinterpret_cast<char*>(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<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

View File

@ -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_); }