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

View File

@ -35,69 +35,42 @@
#ifndef D_BUFFERED_FILE_H
#define D_BUFFERED_FILE_H
#include "OutputFile.h"
#include "IOFile.h"
#include <cstdio>
#include <string>
#include <iosfwd>
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

View File

@ -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<char*>(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<char*>(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<const char*>(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__

View File

@ -38,20 +38,25 @@
#include <zlib.h>
#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

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\
NullOutputFile.h\
console.cc console.h\
IOFile.cc IOFile.h\
BufferedFile.cc BufferedFile.h\
SegList.h\
NullHandle.h\

View File

@ -70,15 +70,15 @@ bool SessionSerializer::save(const std::string& filename) const
std::string tempFilename = filename;
tempFilename += "__temp";
{
SharedHandle<BufferedFile> fp;
SharedHandle<IOFile> 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<Option>& op)
bool writeOption(IOFile& fp, const SharedHandle<Option>& op)
{
const SharedHandle<OptionParser>& oparser = OptionParser::getInstance();
for(size_t i = 1, len = option::countOption(); i < len; ++i) {
@ -151,7 +151,7 @@ bool writeOption(BufferedFile& fp, const SharedHandle<Option>& op)
namespace {
bool writeDownloadResult
(BufferedFile& fp, std::set<a2_gid_t>& metainfoCache,
(IOFile& fp, std::set<a2_gid_t>& metainfoCache,
const SharedHandle<DownloadResult>& dr)
{
const SharedHandle<MetadataInfo>& mi = dr->metadataInfo;
@ -211,7 +211,7 @@ bool writeDownloadResult
}
} // namespace
bool SessionSerializer::save(BufferedFile& fp) const
bool SessionSerializer::save(IOFile& fp) const
{
std::set<a2_gid_t> metainfoCache;
const DownloadResultList& results = rgman_->getDownloadResults();

View File

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

View File

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

View File

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

View File

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