From b0799b6e4627ca7ad483c49e04f17bd40c8feae0 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 23 May 2013 23:12:32 +0900 Subject: [PATCH] Introduce IOFile abstract class to refactor BufferedFile and GZipFile IOFile provides the same interface of old BufferedFile. It provides extension points as pure virtual functions. Those functions are implemented by 2 concrete subclasses: BufferedFile and GZipFile. --- src/BufferedFile.cc | 98 ++++++------------------- src/BufferedFile.h | 59 +++++---------- src/GZipFile.cc | 29 ++++++-- src/GZipFile.h | 25 +++---- src/IOFile.cc | 150 +++++++++++++++++++++++++++++++++++++++ src/IOFile.h | 103 +++++++++++++++++++++++++++ src/Makefile.am | 1 + src/SessionSerializer.cc | 14 ++-- src/SessionSerializer.h | 4 +- src/UriListParser.cc | 4 +- src/UriListParser.h | 4 +- test/BufferedFileTest.cc | 6 +- 12 files changed, 343 insertions(+), 154 deletions(-) create mode 100644 src/IOFile.cc create mode 100644 src/IOFile.h diff --git a/src/BufferedFile.cc b/src/BufferedFile.cc index 62b8e87d..44ea076e 100644 --- a/src/BufferedFile.cc +++ b/src/BufferedFile.cc @@ -43,10 +43,6 @@ namespace aria2 { -const char BufferedFile::READ[] = "rb"; -const char BufferedFile::WRITE[] = "wb"; -const char BufferedFile::APPEND[] = "ab"; - BufferedFile::BufferedFile(const char* filename, const char* mode) : #ifdef __MINGW32__ @@ -67,67 +63,22 @@ BufferedFile::~BufferedFile() close(); } -BufferedFile::operator unspecified_bool_type() const -{ - bool ok = isOpen() && !isError(); - return ok ? &BufferedFile::good_state : 0; -} - -size_t BufferedFile::read(void* ptr, size_t count) +size_t BufferedFile::onRead(void* ptr, size_t count) { return fread(ptr, 1, count, fp_); } -size_t BufferedFile::write(const void* ptr, size_t count) +size_t BufferedFile::onWrite(const void* ptr, size_t count) { return fwrite(ptr, 1, count, fp_); } -size_t BufferedFile::write(const char* str) -{ - return write(str, strlen(str)); -} - -char* BufferedFile::gets(char* s, int size) +char* BufferedFile::onGets(char* s, int size) { return fgets(s, size, fp_); } -char* BufferedFile::getsn(char* s, int size) -{ - char* ptr = gets(s, size); - if(ptr) { - int len = strlen(ptr); - if(ptr[len-1] == '\n') { - ptr[len-1] = '\0'; - } - } - return ptr; -} - -std::string BufferedFile::getLine() -{ - std::string res; - if(eof()) { - return res; - } - char buf[4096]; - while(gets(buf, sizeof(buf))) { - size_t len = strlen(buf); - bool lineBreak = false; - if(buf[len-1] == '\n') { - --len; - lineBreak = true; - } - res.append(buf, len); - if(lineBreak) { - break; - } - } - return res; -} - -int BufferedFile::close() +int BufferedFile::onClose() { if (open_) { open_ = false; @@ -136,39 +87,34 @@ int BufferedFile::close() return 0; } -bool BufferedFile::eof() -{ - return !isOpen()|| isEOF(); -} - -size_t BufferedFile::transfer(std::ostream& out) -{ - size_t count = 0; - char buf[4096]; - while(1) { - size_t r = this->read(buf, sizeof(buf)); - out.write(buf, r); - count += r; - if(r < sizeof(buf)) { - break; - } - } - return count; -} - -int BufferedFile::vprintf(const char* format, va_list va) +int BufferedFile::onVprintf(const char* format, va_list va) { return vfprintf(fp_, format, va); } -int BufferedFile::flush() +int BufferedFile::onFlush() { return fflush(fp_); } -bool BufferedFile::supportsColor() +bool BufferedFile::onSupportsColor() { return supportsColor_; } +bool BufferedFile::isError() const +{ + return ferror(fp_); +} + +bool BufferedFile::isEOF() const +{ + return feof(fp_); +} + +bool BufferedFile::isOpen() const +{ + return open_; +} + } // namespace aria2 diff --git a/src/BufferedFile.h b/src/BufferedFile.h index 7eb6a36d..f3612fc4 100644 --- a/src/BufferedFile.h +++ b/src/BufferedFile.h @@ -35,69 +35,42 @@ #ifndef D_BUFFERED_FILE_H #define D_BUFFERED_FILE_H -#include "OutputFile.h" +#include "IOFile.h" #include -#include -#include namespace aria2 { -// This is a wrapper class for fopen/fclose/fread/fwrite/fgets. -class BufferedFile:public OutputFile { -private: - typedef void (BufferedFile::*unspecified_bool_type)() const; - void good_state() const {} +// IOFILE implementation using standard I/O functions. +class BufferedFile:public IOFile { public: BufferedFile(const char* filename, const char* mode); BufferedFile(FILE* fp); virtual ~BufferedFile(); - // Returns true if file is opened and ferror returns 0. Otherwise - // returns false. - operator unspecified_bool_type() const; +protected: // wrapper for fread. Using 1 for 2nd argument of fread. - virtual size_t read(void* ptr, size_t count); + virtual size_t onRead(void* ptr, size_t count); // wrapper for fwrite. Using 1 for 2nd argument of fwrite. - virtual size_t write(const void* ptr, size_t count); - virtual size_t write(const char* str); + virtual size_t onWrite(const void* ptr, size_t count); // wrapper for fgets - virtual char* gets(char* s, int size); - // wrapper for fgets, but trailing '\n' is replaced with '\0'. - char* getsn(char* s, int size); - // Reads one line and returns it. The last '\n' is removed. - std::string getLine(); - // wrapper for fclose - virtual int close(); - // Return true if open_ && feof(fp_) != 0. Otherwise returns false. - bool eof(); - // Convenient method. Read data to end of file and write them into - // given stream. Returns written size. - size_t transfer(std::ostream& out); - virtual int vprintf(const char* format, va_list va); + virtual char* onGets(char* s, int size); + virtual int onVprintf(const char* format, va_list va); // wrapper for fflush - virtual int flush(); - virtual bool supportsColor(); - // Mode for reading - static const char READ[]; - // Mode for writing - static const char WRITE[]; - // Mode for append - static const char APPEND[]; - + virtual int onFlush(); + // wrapper for fclose + virtual int onClose(); + virtual bool onSupportsColor(); + virtual bool isError() const; + virtual bool isEOF() const; + virtual bool isOpen() const; private: - // Don't allow copying + // Don't allow copying; BufferedFile(const BufferedFile&); BufferedFile& operator=(const BufferedFile&); FILE* fp_; bool open_; bool supportsColor_; - -protected: - virtual bool isError() const { return ferror(fp_); } - virtual bool isEOF() const { return feof(fp_); } - virtual bool isOpen() const { return open_; } - }; } // namespace aria2 diff --git a/src/GZipFile.cc b/src/GZipFile.cc index b3662227..f7685cc9 100644 --- a/src/GZipFile.cc +++ b/src/GZipFile.cc @@ -44,7 +44,7 @@ namespace aria2 { GZipFile::GZipFile(const char* filename, const char* mode) - : BufferedFile(0), fp_(0), open_(false), + : fp_(0), open_(false), buflen_(1024), buf_(reinterpret_cast(malloc(buflen_))) { FILE* fp = @@ -81,7 +81,7 @@ GZipFile::~GZipFile() free(buf_); } -int GZipFile::close() +int GZipFile::onClose() { if (open_) { open_ = false; @@ -90,6 +90,11 @@ int GZipFile::close() return 0; } +bool GZipFile::onSupportsColor() +{ + return false; +} + bool GZipFile::isError() const { int rv = 0; @@ -97,7 +102,17 @@ bool GZipFile::isError() const return (e != 0 && *e != 0) || rv != 0; } -size_t GZipFile::read(void* ptr, size_t count) +bool GZipFile::isEOF() const +{ + return gzeof(fp_); +} + +bool GZipFile::isOpen() const +{ + return open_; +} + +size_t GZipFile::onRead(void* ptr, size_t count) { char *data = reinterpret_cast(ptr); size_t read = 0; @@ -114,7 +129,7 @@ size_t GZipFile::read(void* ptr, size_t count) return read; } -size_t GZipFile::write(const void* ptr, size_t count) +size_t GZipFile::onWrite(const void* ptr, size_t count) { const char *data = reinterpret_cast(ptr); size_t written = 0; @@ -131,17 +146,17 @@ size_t GZipFile::write(const void* ptr, size_t count) return written; } -char* GZipFile::gets(char* s, int size) +char* GZipFile::onGets(char* s, int size) { return gzgets(fp_, s, size); } -int GZipFile::flush() +int GZipFile::onFlush() { return gzflush(fp_, 0); } -int GZipFile::vprintf(const char* format, va_list va) +int GZipFile::onVprintf(const char* format, va_list va) { ssize_t len; #ifdef __MINGW32__ diff --git a/src/GZipFile.h b/src/GZipFile.h index 4e612624..f02c8df6 100644 --- a/src/GZipFile.h +++ b/src/GZipFile.h @@ -38,20 +38,25 @@ #include -#include "BufferedFile.h" +#include "IOFile.h" namespace aria2 { -class GZipFile: public BufferedFile { +class GZipFile: public IOFile { public: GZipFile(const char* filename, const char* mode); virtual ~GZipFile(); - virtual int close(); - virtual size_t read(void* ptr, size_t count); - virtual size_t write(const void* ptr, size_t count); - virtual char* gets(char* s, int size); - virtual int vprintf(const char* format, va_list va); - virtual int flush(); +protected: + virtual size_t onRead(void* ptr, size_t count); + virtual size_t onWrite(const void* ptr, size_t count); + virtual char* onGets(char* s, int size); + virtual int onVprintf(const char* format, va_list va); + virtual int onFlush(); + virtual int onClose(); + virtual bool onSupportsColor(); + virtual bool isError() const; + virtual bool isEOF() const; + virtual bool isOpen() const; private: // Don't allow copying GZipFile(const GZipFile&); @@ -62,10 +67,6 @@ private: size_t buflen_; char* buf_; -protected: - virtual bool isError() const; - virtual bool isEOF() const { return gzeof(fp_); } - virtual bool isOpen() const { return open_; } }; } // namespace aria2 diff --git a/src/IOFile.cc b/src/IOFile.cc new file mode 100644 index 00000000..5088f584 --- /dev/null +++ b/src/IOFile.cc @@ -0,0 +1,150 @@ +/* */ +#include "IOFile.h" + +#include +#include +#include + +#include "a2io.h" +#include "util.h" + +namespace aria2 { + +const char IOFile::READ[] = "rb"; +const char IOFile::WRITE[] = "wb"; +const char IOFile::APPEND[] = "ab"; + +IOFile::operator unspecified_bool_type() const +{ + bool ok = isOpen() && !isError(); + return ok ? &IOFile::goodState : 0; +} + +size_t IOFile::read(void* ptr, size_t count) +{ + return onRead(ptr, count); +} + +size_t IOFile::write(const void* ptr, size_t count) +{ + return onWrite(ptr, count); +} + +size_t IOFile::write(const char* str) +{ + return write(str, strlen(str)); +} + +char* IOFile::gets(char* s, int size) +{ + return onGets(s, size); +} + +char* IOFile::getsn(char* s, int size) +{ + char* ptr = gets(s, size); + if(ptr) { + int len = strlen(ptr); + if(ptr[len-1] == '\n') { + ptr[len-1] = '\0'; + } + } + return ptr; +} + +std::string IOFile::getLine() +{ + std::string res; + if(eof()) { + return res; + } + char buf[4096]; + while(gets(buf, sizeof(buf))) { + size_t len = strlen(buf); + bool lineBreak = false; + if(buf[len-1] == '\n') { + --len; + lineBreak = true; + } + res.append(buf, len); + if(lineBreak) { + break; + } + } + return res; +} + +int IOFile::close() +{ + return onClose(); +} + +bool IOFile::eof() +{ + return !isOpen() || isEOF(); +} + +size_t IOFile::transfer(std::ostream& out) +{ + size_t count = 0; + char buf[4096]; + while(1) { + size_t r = this->read(buf, sizeof(buf)); + out.write(buf, r); + count += r; + if(r < sizeof(buf)) { + break; + } + } + return count; +} + +int IOFile::vprintf(const char* format, va_list va) +{ + return onVprintf(format, va); +} + +int IOFile::flush() +{ + return onFlush(); +} + +bool IOFile::supportsColor() +{ + return onSupportsColor(); +} + +} // namespace aria2 diff --git a/src/IOFile.h b/src/IOFile.h new file mode 100644 index 00000000..12666c2a --- /dev/null +++ b/src/IOFile.h @@ -0,0 +1,103 @@ +/* */ +#ifndef D_IO_FILE_H +#define D_IO_FILE_H + +#include "OutputFile.h" + +#include +#include + +namespace aria2 { + +// This is a wrapper base class intended to provide +// fopen/fclose/fread/fwrite/fgets functionality. +class IOFile:public OutputFile { +private: + typedef void (IOFile::*unspecified_bool_type)() const; + void goodState() const {} +public: + IOFile() {} + virtual ~IOFile() {} + // Returns true if file is opened and ferror returns 0. Otherwise + // returns false. + operator unspecified_bool_type() const; + // wrapper for fread. Using 1 for 2nd argument of fread. + size_t read(void* ptr, size_t count); + // wrapper for fwrite. Using 1 for 2nd argument of fwrite. + size_t write(const void* ptr, size_t count); + virtual size_t write(const char* str); + // wrapper for fgets + char* gets(char* s, int size); + // wrapper for fgets, but trailing '\n' is replaced with '\0'. + char* getsn(char* s, int size); + // Reads one line and returns it. The last '\n' is removed. + std::string getLine(); + // wrapper for fclose + int close(); + // wrapper for fflush + int flush(); + // Return true if file is opened && feof(fp_) != 0. Otherwise + // returns false. + bool eof(); + // Returns true if file supports ANSI color escape codes. + bool supportsColor(); + // Convenient method. Read data to end of file and write them into + // given stream. Returns written size. + size_t transfer(std::ostream& out); + int vprintf(const char* format, va_list va); + // Mode for reading + static const char READ[]; + // Mode for writing + static const char WRITE[]; + // Mode for append + static const char APPEND[]; +protected: + virtual size_t onRead(void* ptr, size_t count) = 0; + virtual size_t onWrite(const void* ptr, size_t count) = 0; + virtual char* onGets(char* s, int size) = 0; + virtual int onVprintf(const char* format, va_list va) = 0; + virtual int onFlush() = 0; + virtual int onClose() = 0; + virtual bool onSupportsColor() = 0; + + virtual bool isError() const = 0; + virtual bool isEOF() const = 0; + virtual bool isOpen() const = 0; +}; + +} // namespace aria2 + +#endif // D_IO_FILE_H diff --git a/src/Makefile.am b/src/Makefile.am index 28a40c47..c97b5b8e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -229,6 +229,7 @@ SRCS = option_processing.cc\ OutputFile.h\ NullOutputFile.h\ console.cc console.h\ + IOFile.cc IOFile.h\ BufferedFile.cc BufferedFile.h\ SegList.h\ NullHandle.h\ diff --git a/src/SessionSerializer.cc b/src/SessionSerializer.cc index 5de35709..37dfe7b8 100644 --- a/src/SessionSerializer.cc +++ b/src/SessionSerializer.cc @@ -70,15 +70,15 @@ bool SessionSerializer::save(const std::string& filename) const std::string tempFilename = filename; tempFilename += "__temp"; { - SharedHandle fp; + SharedHandle fp; #if HAVE_ZLIB if (util::endsWith(filename, ".gz")) { - fp.reset(new GZipFile(tempFilename.c_str(), BufferedFile::WRITE)); + fp.reset(new GZipFile(tempFilename.c_str(), IOFile::WRITE)); } else #endif { - fp.reset(new BufferedFile(tempFilename.c_str(), BufferedFile::WRITE)); + fp.reset(new BufferedFile(tempFilename.c_str(), IOFile::WRITE)); } if(!*fp) { return false; @@ -93,7 +93,7 @@ bool SessionSerializer::save(const std::string& filename) const namespace { // Write 1 line of option name/value pair. This function returns true // if it succeeds, or false. -bool writeOptionLine(BufferedFile& fp, const Pref* pref, +bool writeOptionLine(IOFile& fp, const Pref* pref, const std::string& val) { size_t prefLen = strlen(pref->k); @@ -106,7 +106,7 @@ bool writeOptionLine(BufferedFile& fp, const Pref* pref, } // namespace namespace { -bool writeOption(BufferedFile& fp, const SharedHandle