Ver Fonte

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.
Tatsuhiro Tsujikawa há 12 anos atrás
pai
commit
43cb2d880a
2 ficheiros alterados com 47 adições e 18 exclusões
  1. 44 17
      src/GZipFile.cc
  2. 3 1
      src/GZipFile.h

+ 44 - 17
src/GZipFile.cc

@@ -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

+ 3 - 1
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_); }