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.
pull/97/head
Tatsuhiro Tsujikawa 2013-05-23 23:12:32 +09:00
parent 6c0fa43fa5
commit b0799b6e46
12 changed files with 343 additions and 154 deletions

View File

@ -43,10 +43,6 @@
namespace aria2 { 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) BufferedFile::BufferedFile(const char* filename, const char* mode)
: :
#ifdef __MINGW32__ #ifdef __MINGW32__
@ -67,67 +63,22 @@ BufferedFile::~BufferedFile()
close(); close();
} }
BufferedFile::operator unspecified_bool_type() const size_t BufferedFile::onRead(void* ptr, size_t count)
{
bool ok = isOpen() && !isError();
return ok ? &BufferedFile::good_state : 0;
}
size_t BufferedFile::read(void* ptr, size_t count)
{ {
return fread(ptr, 1, count, fp_); 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_); return fwrite(ptr, 1, count, fp_);
} }
size_t BufferedFile::write(const char* str) char* BufferedFile::onGets(char* s, int size)
{
return write(str, strlen(str));
}
char* BufferedFile::gets(char* s, int size)
{ {
return fgets(s, size, fp_); return fgets(s, size, fp_);
} }
char* BufferedFile::getsn(char* s, int size) int BufferedFile::onClose()
{
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()
{ {
if (open_) { if (open_) {
open_ = false; open_ = false;
@ -136,39 +87,34 @@ int BufferedFile::close()
return 0; return 0;
} }
bool BufferedFile::eof() int BufferedFile::onVprintf(const char* format, va_list va)
{
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)
{ {
return vfprintf(fp_, format, va); return vfprintf(fp_, format, va);
} }
int BufferedFile::flush() int BufferedFile::onFlush()
{ {
return fflush(fp_); return fflush(fp_);
} }
bool BufferedFile::supportsColor() bool BufferedFile::onSupportsColor()
{ {
return supportsColor_; return supportsColor_;
} }
bool BufferedFile::isError() const
{
return ferror(fp_);
}
bool BufferedFile::isEOF() const
{
return feof(fp_);
}
bool BufferedFile::isOpen() const
{
return open_;
}
} // namespace aria2 } // namespace aria2

View File

@ -35,69 +35,42 @@
#ifndef D_BUFFERED_FILE_H #ifndef D_BUFFERED_FILE_H
#define D_BUFFERED_FILE_H #define D_BUFFERED_FILE_H
#include "OutputFile.h" #include "IOFile.h"
#include <cstdio> #include <cstdio>
#include <string>
#include <iosfwd>
namespace aria2 { namespace aria2 {
// This is a wrapper class for fopen/fclose/fread/fwrite/fgets. // IOFILE implementation using standard I/O functions.
class BufferedFile:public OutputFile { class BufferedFile:public IOFile {
private:
typedef void (BufferedFile::*unspecified_bool_type)() const;
void good_state() const {}
public: public:
BufferedFile(const char* filename, const char* mode); BufferedFile(const char* filename, const char* mode);
BufferedFile(FILE* fp); BufferedFile(FILE* fp);
virtual ~BufferedFile(); virtual ~BufferedFile();
// Returns true if file is opened and ferror returns 0. Otherwise protected:
// returns false.
operator unspecified_bool_type() const;
// wrapper for fread. Using 1 for 2nd argument of fread. // 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. // wrapper for fwrite. Using 1 for 2nd argument of fwrite.
virtual size_t write(const void* ptr, size_t count); virtual size_t onWrite(const void* ptr, size_t count);
virtual size_t write(const char* str);
// wrapper for fgets // wrapper for fgets
virtual char* gets(char* s, int size); virtual char* onGets(char* s, int size);
// wrapper for fgets, but trailing '\n' is replaced with '\0'. virtual int onVprintf(const char* format, va_list va);
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);
// wrapper for fflush // wrapper for fflush
virtual int flush(); virtual int onFlush();
virtual bool supportsColor(); // wrapper for fclose
// Mode for reading virtual int onClose();
static const char READ[]; virtual bool onSupportsColor();
// Mode for writing virtual bool isError() const;
static const char WRITE[]; virtual bool isEOF() const;
// Mode for append virtual bool isOpen() const;
static const char APPEND[];
private: private:
// Don't allow copying // Don't allow copying;
BufferedFile(const BufferedFile&); BufferedFile(const BufferedFile&);
BufferedFile& operator=(const BufferedFile&); BufferedFile& operator=(const BufferedFile&);
FILE* fp_; FILE* fp_;
bool open_; bool open_;
bool supportsColor_; 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 } // namespace aria2

View File

@ -44,7 +44,7 @@
namespace aria2 { namespace aria2 {
GZipFile::GZipFile(const char* filename, const char* mode) GZipFile::GZipFile(const char* filename, const char* mode)
: BufferedFile(0), fp_(0), open_(false), : fp_(0), open_(false),
buflen_(1024), buf_(reinterpret_cast<char*>(malloc(buflen_))) buflen_(1024), buf_(reinterpret_cast<char*>(malloc(buflen_)))
{ {
FILE* fp = FILE* fp =
@ -81,7 +81,7 @@ GZipFile::~GZipFile()
free(buf_); free(buf_);
} }
int GZipFile::close() int GZipFile::onClose()
{ {
if (open_) { if (open_) {
open_ = false; open_ = false;
@ -90,6 +90,11 @@ int GZipFile::close()
return 0; return 0;
} }
bool GZipFile::onSupportsColor()
{
return false;
}
bool GZipFile::isError() const bool GZipFile::isError() const
{ {
int rv = 0; int rv = 0;
@ -97,7 +102,17 @@ bool GZipFile::isError() const
return (e != 0 && *e != 0) || rv != 0; 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<char*>(ptr); char *data = reinterpret_cast<char*>(ptr);
size_t read = 0; size_t read = 0;
@ -114,7 +129,7 @@ size_t GZipFile::read(void* ptr, size_t count)
return read; 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<const char*>(ptr); const char *data = reinterpret_cast<const char*>(ptr);
size_t written = 0; size_t written = 0;
@ -131,17 +146,17 @@ size_t GZipFile::write(const void* ptr, size_t count)
return written; return written;
} }
char* GZipFile::gets(char* s, int size) char* GZipFile::onGets(char* s, int size)
{ {
return gzgets(fp_, s, size); return gzgets(fp_, s, size);
} }
int GZipFile::flush() int GZipFile::onFlush()
{ {
return gzflush(fp_, 0); 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; ssize_t len;
#ifdef __MINGW32__ #ifdef __MINGW32__

View File

@ -38,20 +38,25 @@
#include <zlib.h> #include <zlib.h>
#include "BufferedFile.h" #include "IOFile.h"
namespace aria2 { namespace aria2 {
class GZipFile: public BufferedFile { class GZipFile: public IOFile {
public: public:
GZipFile(const char* filename, const char* mode); GZipFile(const char* filename, const char* mode);
virtual ~GZipFile(); virtual ~GZipFile();
virtual int close(); protected:
virtual size_t read(void* ptr, size_t count); virtual size_t onRead(void* ptr, size_t count);
virtual size_t write(const void* ptr, size_t count); virtual size_t onWrite(const void* ptr, size_t count);
virtual char* gets(char* s, int size); virtual char* onGets(char* s, int size);
virtual int vprintf(const char* format, va_list va); virtual int onVprintf(const char* format, va_list va);
virtual int flush(); virtual int onFlush();
virtual int onClose();
virtual bool onSupportsColor();
virtual bool isError() const;
virtual bool isEOF() const;
virtual bool isOpen() const;
private: private:
// Don't allow copying // Don't allow copying
GZipFile(const GZipFile&); GZipFile(const GZipFile&);
@ -62,10 +67,6 @@ private:
size_t buflen_; size_t buflen_;
char* buf_; char* buf_;
protected:
virtual bool isError() const;
virtual bool isEOF() const { return gzeof(fp_); }
virtual bool isOpen() const { return open_; }
}; };
} // namespace aria2 } // namespace aria2

150
src/IOFile.cc Normal file
View File

@ -0,0 +1,150 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2011 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#include "IOFile.h"
#include <cstring>
#include <cstdarg>
#include <ostream>
#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

103
src/IOFile.h Normal file
View File

@ -0,0 +1,103 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2011 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#ifndef D_IO_FILE_H
#define D_IO_FILE_H
#include "OutputFile.h"
#include <string>
#include <iosfwd>
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

View File

@ -229,6 +229,7 @@ SRCS = option_processing.cc\
OutputFile.h\ OutputFile.h\
NullOutputFile.h\ NullOutputFile.h\
console.cc console.h\ console.cc console.h\
IOFile.cc IOFile.h\
BufferedFile.cc BufferedFile.h\ BufferedFile.cc BufferedFile.h\
SegList.h\ SegList.h\
NullHandle.h\ NullHandle.h\

View File

@ -70,15 +70,15 @@ bool SessionSerializer::save(const std::string& filename) const
std::string tempFilename = filename; std::string tempFilename = filename;
tempFilename += "__temp"; tempFilename += "__temp";
{ {
SharedHandle<BufferedFile> fp; SharedHandle<IOFile> fp;
#if HAVE_ZLIB #if HAVE_ZLIB
if (util::endsWith(filename, ".gz")) { if (util::endsWith(filename, ".gz")) {
fp.reset(new GZipFile(tempFilename.c_str(), BufferedFile::WRITE)); fp.reset(new GZipFile(tempFilename.c_str(), IOFile::WRITE));
} }
else else
#endif #endif
{ {
fp.reset(new BufferedFile(tempFilename.c_str(), BufferedFile::WRITE)); fp.reset(new BufferedFile(tempFilename.c_str(), IOFile::WRITE));
} }
if(!*fp) { if(!*fp) {
return false; return false;
@ -93,7 +93,7 @@ bool SessionSerializer::save(const std::string& filename) const
namespace { namespace {
// Write 1 line of option name/value pair. This function returns true // Write 1 line of option name/value pair. This function returns true
// if it succeeds, or false. // if it succeeds, or false.
bool writeOptionLine(BufferedFile& fp, const Pref* pref, bool writeOptionLine(IOFile& fp, const Pref* pref,
const std::string& val) const std::string& val)
{ {
size_t prefLen = strlen(pref->k); size_t prefLen = strlen(pref->k);
@ -106,7 +106,7 @@ bool writeOptionLine(BufferedFile& fp, const Pref* pref,
} // namespace } // namespace
namespace { namespace {
bool writeOption(BufferedFile& fp, const SharedHandle<Option>& op) bool writeOption(IOFile& fp, const SharedHandle<Option>& op)
{ {
const SharedHandle<OptionParser>& oparser = OptionParser::getInstance(); const SharedHandle<OptionParser>& oparser = OptionParser::getInstance();
for(size_t i = 1, len = option::countOption(); i < len; ++i) { for(size_t i = 1, len = option::countOption(); i < len; ++i) {
@ -151,7 +151,7 @@ bool writeOption(BufferedFile& fp, const SharedHandle<Option>& op)
namespace { namespace {
bool writeDownloadResult bool writeDownloadResult
(BufferedFile& fp, std::set<a2_gid_t>& metainfoCache, (IOFile& fp, std::set<a2_gid_t>& metainfoCache,
const SharedHandle<DownloadResult>& dr) const SharedHandle<DownloadResult>& dr)
{ {
const SharedHandle<MetadataInfo>& mi = dr->metadataInfo; const SharedHandle<MetadataInfo>& mi = dr->metadataInfo;
@ -211,7 +211,7 @@ bool writeDownloadResult
} }
} // namespace } // namespace
bool SessionSerializer::save(BufferedFile& fp) const bool SessionSerializer::save(IOFile& fp) const
{ {
std::set<a2_gid_t> metainfoCache; std::set<a2_gid_t> metainfoCache;
const DownloadResultList& results = rgman_->getDownloadResults(); const DownloadResultList& results = rgman_->getDownloadResults();

View File

@ -45,7 +45,7 @@
namespace aria2 { namespace aria2 {
class RequestGroupMan; class RequestGroupMan;
class BufferedFile; class IOFile;
class SessionSerializer { class SessionSerializer {
private: private:
@ -53,7 +53,7 @@ private:
bool saveError_; bool saveError_;
bool saveInProgress_; bool saveInProgress_;
bool saveWaiting_; bool saveWaiting_;
bool save(BufferedFile& fp) const; bool save(IOFile& fp) const;
public: public:
SessionSerializer(const SharedHandle<RequestGroupMan>& requestGroupMan); SessionSerializer(const SharedHandle<RequestGroupMan>& requestGroupMan);

View File

@ -53,9 +53,9 @@ namespace aria2 {
UriListParser::UriListParser(const std::string& filename) UriListParser::UriListParser(const std::string& filename)
#if HAVE_ZLIB #if HAVE_ZLIB
: fp_(new GZipFile(filename.c_str(), BufferedFile::READ)) : fp_(new GZipFile(filename.c_str(), IOFile::READ))
#else #else
: fp_(new BufferedFile(filename.c_str(), BufferedFile::READ)) : fp_(new BufferedFile(filename.c_str(), IOFile::READ))
#endif #endif
{} {}

View File

@ -42,14 +42,14 @@
#include <iosfwd> #include <iosfwd>
#include "Option.h" #include "Option.h"
#include "BufferedFile.h" #include "IOFile.h"
#include "SharedHandle.h" #include "SharedHandle.h"
namespace aria2 { namespace aria2 {
class UriListParser { class UriListParser {
private: private:
SharedHandle<BufferedFile> fp_; SharedHandle<IOFile> fp_;
std::string line_; std::string line_;
public: public:

View File

@ -24,16 +24,16 @@ void BufferedFileTest::testOpen()
{ {
File f(A2_TEST_OUT_DIR"/aria2_BufferedFileTest_testOpen"); File f(A2_TEST_OUT_DIR"/aria2_BufferedFileTest_testOpen");
f.remove(); f.remove();
BufferedFile fail(f.getPath().c_str(), BufferedFile::READ); BufferedFile fail(f.getPath().c_str(), IOFile::READ);
CPPUNIT_ASSERT(!fail); CPPUNIT_ASSERT(!fail);
BufferedFile wr(f.getPath().c_str(), BufferedFile::WRITE); BufferedFile wr(f.getPath().c_str(), IOFile::WRITE);
CPPUNIT_ASSERT(wr); CPPUNIT_ASSERT(wr);
std::string msg = "aria2 rules\nalpha\nbravo\ncharlie"; std::string msg = "aria2 rules\nalpha\nbravo\ncharlie";
wr.write(msg.data(), msg.size()); wr.write(msg.data(), msg.size());
wr.close(); wr.close();
BufferedFile rd(f.getPath().c_str(), BufferedFile::READ); BufferedFile rd(f.getPath().c_str(), IOFile::READ);
char buf[256]; char buf[256];
size_t len = rd.read(buf, 11); size_t len = rd.read(buf, 11);
CPPUNIT_ASSERT_EQUAL((size_t)11, len); CPPUNIT_ASSERT_EQUAL((size_t)11, len);