OSDN Git Service

reader_interfaceのファイル読み出しにおける実装であるFileReaderを追加した。
authorderui <derutakayu@user.sourceforge.jp>
Mon, 30 Nov 2009 15:00:00 +0000 (00:00 +0900)
committerderui <derutakayu@user.sourceforge.jp>
Mon, 30 Nov 2009 15:00:00 +0000 (00:00 +0900)
reader_interface::Seekのインターフェースを変更。
file_readerのtestを追加。

12 files changed:
autom4te.cache/requests
config.log
src/file_reader.cpp [new file with mode: 0755]
src/file_reader.h [new file with mode: 0755]
src/reader_interface.h
src/string_reader.cpp
src/string_reader.h
src/test/Makefile
src/test/Makefile.am
src/test/Makefile.in
src/test/file_reader_test.cpp [new file with mode: 0755]
src/test/string_reader_test.cpp

index 02bca84..e9c9fae 100644 (file)
                         'configure.in'
                       ],
                       {
-                        'AM_PROG_F77_C_O' => 1,
                         '_LT_AC_TAGCONFIG' => 1,
-                        'm4_pattern_forbid' => 1,
+                        'AM_PROG_F77_C_O' => 1,
                         'AC_INIT' => 1,
-                        '_AM_COND_IF' => 1,
+                        'm4_pattern_forbid' => 1,
                         'AC_CANONICAL_TARGET' => 1,
-                        'AC_SUBST' => 1,
+                        '_AM_COND_IF' => 1,
                         'AC_CONFIG_LIBOBJ_DIR' => 1,
-                        'AC_FC_SRCEXT' => 1,
+                        'AC_SUBST' => 1,
                         'AC_CANONICAL_HOST' => 1,
+                        'AC_FC_SRCEXT' => 1,
                         'AC_PROG_LIBTOOL' => 1,
                         'AM_INIT_AUTOMAKE' => 1,
                         'AC_CONFIG_SUBDIRS' => 1,
                         'AM_AUTOMAKE_VERSION' => 1,
                         'LT_CONFIG_LTDL_DIR' => 1,
-                        'AC_CONFIG_LINKS' => 1,
                         'AC_REQUIRE_AUX_FILE' => 1,
-                        'm4_sinclude' => 1,
+                        'AC_CONFIG_LINKS' => 1,
                         'LT_SUPPORTED_TAG' => 1,
+                        'm4_sinclude' => 1,
                         'AM_MAINTAINER_MODE' => 1,
                         'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
                         '_m4_warn' => 1,
                         'AC_CANONICAL_BUILD' => 1,
                         'AC_FC_FREEFORM' => 1,
                         'AH_OUTPUT' => 1,
-                        '_AM_SUBST_NOTMAKE' => 1,
                         'AC_CONFIG_AUX_DIR' => 1,
-                        'sinclude' => 1,
-                        'AM_PROG_CC_C_O' => 1,
+                        '_AM_SUBST_NOTMAKE' => 1,
                         'm4_pattern_allow' => 1,
-                        'AC_CANONICAL_SYSTEM' => 1,
+                        'AM_PROG_CC_C_O' => 1,
+                        'sinclude' => 1,
                         'AM_CONDITIONAL' => 1,
+                        'AC_CANONICAL_SYSTEM' => 1,
                         'AC_CONFIG_HEADERS' => 1,
                         'AC_DEFINE_TRACE_LITERAL' => 1,
                         'm4_include' => 1,
                         'configure.in'
                       ],
                       {
-                        'AM_PROG_F77_C_O' => 1,
                         '_LT_AC_TAGCONFIG' => 1,
-                        'm4_pattern_forbid' => 1,
+                        'AM_PROG_F77_C_O' => 1,
                         'AC_INIT' => 1,
-                        'AC_CANONICAL_TARGET' => 1,
+                        'm4_pattern_forbid' => 1,
                         '_AM_COND_IF' => 1,
-                        'AC_CONFIG_LIBOBJ_DIR' => 1,
+                        'AC_CANONICAL_TARGET' => 1,
                         'AC_SUBST' => 1,
-                        'AC_CANONICAL_HOST' => 1,
+                        'AC_CONFIG_LIBOBJ_DIR' => 1,
                         'AC_FC_SRCEXT' => 1,
+                        'AC_CANONICAL_HOST' => 1,
                         'AC_PROG_LIBTOOL' => 1,
                         'AM_INIT_AUTOMAKE' => 1,
                         'AC_CONFIG_SUBDIRS' => 1,
                         'AM_AUTOMAKE_VERSION' => 1,
                         'LT_CONFIG_LTDL_DIR' => 1,
-                        'AC_CONFIG_LINKS' => 1,
                         'AC_REQUIRE_AUX_FILE' => 1,
-                        'LT_SUPPORTED_TAG' => 1,
+                        'AC_CONFIG_LINKS' => 1,
                         'm4_sinclude' => 1,
+                        'LT_SUPPORTED_TAG' => 1,
                         'AM_MAINTAINER_MODE' => 1,
                         'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
                         '_m4_warn' => 1,
                         'AC_CANONICAL_BUILD' => 1,
                         'AC_FC_FREEFORM' => 1,
                         'AH_OUTPUT' => 1,
-                        'AC_CONFIG_AUX_DIR' => 1,
                         '_AM_SUBST_NOTMAKE' => 1,
-                        'AM_PROG_CC_C_O' => 1,
-                        'm4_pattern_allow' => 1,
+                        'AC_CONFIG_AUX_DIR' => 1,
                         'sinclude' => 1,
-                        'AM_CONDITIONAL' => 1,
+                        'm4_pattern_allow' => 1,
+                        'AM_PROG_CC_C_O' => 1,
                         'AC_CANONICAL_SYSTEM' => 1,
+                        'AM_CONDITIONAL' => 1,
                         'AC_CONFIG_HEADERS' => 1,
                         'AC_DEFINE_TRACE_LITERAL' => 1,
                         'm4_include' => 1,
index a58c380..b101d1c 100644 (file)
@@ -859,3 +859,55 @@ on vaio_z
 
 config.status:777: creating src/test/Makefile
 config.status:1051: executing depfiles commands
+
+## ---------------------- ##
+## Running config.status. ##
+## ---------------------- ##
+
+This file was extended by utakata config.status 0.0.1, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  CONFIG_FILES    = 
+  CONFIG_HEADERS  = 
+  CONFIG_LINKS    = 
+  CONFIG_COMMANDS = 
+  $ ./config.status Makefile
+
+on vaio_z
+
+config.status:777: creating Makefile
+
+## ---------------------- ##
+## Running config.status. ##
+## ---------------------- ##
+
+This file was extended by utakata config.status 0.0.1, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  CONFIG_FILES    = 
+  CONFIG_HEADERS  = 
+  CONFIG_LINKS    = 
+  CONFIG_COMMANDS = 
+  $ ./config.status src/Makefile
+
+on vaio_z
+
+config.status:777: creating src/Makefile
+
+## ---------------------- ##
+## Running config.status. ##
+## ---------------------- ##
+
+This file was extended by utakata config.status 0.0.1, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  CONFIG_FILES    = 
+  CONFIG_HEADERS  = 
+  CONFIG_LINKS    = 
+  CONFIG_COMMANDS = 
+  $ ./config.status src/test/Makefile depfiles
+
+on vaio_z
+
+config.status:777: creating src/test/Makefile
+config.status:1051: executing depfiles commands
diff --git a/src/file_reader.cpp b/src/file_reader.cpp
new file mode 100755 (executable)
index 0000000..9b762c4
--- /dev/null
@@ -0,0 +1,203 @@
+//
+// reader::FileReaderの実装を提供します。
+//
+// FileReaderは、ファイルからのバイト単位の読み出しをサポートします。
+// FileReaderでは、ファイルからの読出時にエンコーディングを考慮しません。
+//
+// FileReaderにおける読み出し位置は、先頭が0であるとされます。
+// 4文字渡して、2文字読出した時点で2となります。
+//
+#include <cstdio>
+#include <algorithm>
+
+#include "src/file_reader.h"
+
+namespace reader = utakata::reader;
+
+reader::FileReader::~FileReader() {
+  if (file_pointer_ != NULL) {
+    ::fclose(file_pointer_);
+  }
+  file_pointer_ = NULL;
+}
+
+// ファイルをオープンする際、各情報は完全に初期化されます。
+// 読出位置の復元などはサポートしません。
+bool reader::FileReader::Open() {
+  if (filename_.empty()) {
+    return false;
+  }
+
+  pos_ = 0;
+  file_pointer_ = ::fopen(filename_.c_str(), "rb");
+  if (file_pointer_ == NULL) {
+    file_size_ = 0;
+    return false;
+  }
+
+  ::fseek(file_pointer_, 0, SEEK_END);
+  file_size_ = ::ftell(file_pointer_);
+  ::fseek(file_pointer_, 0, SEEK_SET);
+
+  return true;
+}
+
+void reader::FileReader::Close() {
+  if (IsOpened()) {
+    ::fclose(file_pointer_);
+    file_size_ = 0;
+    pos_ = 0;
+    file_pointer_ = NULL;
+  }
+}
+
+// ファイルから1バイト読み出す際には::freadを利用します。
+// 返り値の調査で1バイト読み出せているかをチェックし、例外の送出
+// 判断を行っています。
+unsigned char reader::FileReader::Read() {
+  CheckOpened();
+  CheckEOF();
+
+  unsigned char byte = 0;
+  if (::fread(&byte, 1, 1, file_pointer_) != 1) {
+    throw reader::IOException("file read error! `" + filename_ + "`");
+  }
+
+  ++pos_;
+
+  return byte;
+}
+
+// ファイルからの読み出しには::freadを利用します。
+// 返り値の調査で指定のバイト数を読み出せているかをチェックし、
+// 例外の送出判断を行っています。
+std::vector<unsigned char> reader::FileReader::Read(size_t num) {
+  CheckOpened();
+  CheckEOF();
+
+  if (num <= 0)
+  {
+    return std::vector<unsigned char>();
+  }
+
+  std::vector<unsigned char> ret(num + 1, 0);
+  int readed = ::fread(&ret[0], 1, num, file_pointer_);
+
+  pos_ += readed;
+
+  return ret;
+}
+
+// 1バイトだけ読出を行うため、1バイトだけ読出を行い、1バイト戻しています。
+unsigned char reader::FileReader::Peek() {
+  CheckOpened();
+  CheckEOF();
+  
+  unsigned char byte = Read();
+  Seek(1, reader::kBackward);
+
+  return byte;
+}
+
+// 指定された数量だけ読み出して、読み出せた分だけ戻しています。
+std::vector<unsigned char> reader::FileReader::Peek(size_t num) {
+  CheckOpened();
+  CheckEOF();
+
+  if (num <= 0)
+  {
+    return std::vector<unsigned char>();
+  }
+
+  std::vector<unsigned char> ret = Read(num);
+  Seek(ret.size(), reader::kBackward);
+  return ret;
+}
+
+// 読出位置は、Peekのみ更新されません。
+size_t reader::FileReader::GetPos() const {
+  return pos_;
+}
+
+// 読出が成功するかどうかはfseekの戻り値によります。
+bool reader::FileReader::Seek(
+    int seekpos, reader::SeekDirection direction) {
+  CheckOpened();
+
+  if (seekpos <= 0) {
+    return false;
+  }
+
+  if (direction == reader::kBackward) {
+    seekpos *= -1;
+  }
+
+  int seeked = ::fseek(file_pointer_, seekpos, SEEK_CUR);
+  if (seeked) {
+    return false;
+  }
+  size_t seek_after_pos = ::ftell(file_pointer_);
+  pos_ = seek_after_pos;
+
+  return true;
+}
+
+// fseek前後のposを比較して、移動量を算出しています。
+bool reader::FileReader::Seek(
+    int seekpos, reader::SeekDirection direction,
+                              size_t *seek_difference) {
+  CheckOpened();
+
+  if (seekpos <= 0) {
+    return false;
+  }
+
+  if (direction == reader::kBackward) {
+    seekpos *= -1;
+  }
+
+  int seek_previous_pos = pos_;
+  int seeked = ::fseek(file_pointer_, seekpos, SEEK_CUR);
+  if (seeked) {
+    return false;
+  }
+  int seek_after_pos = ::ftell(file_pointer_);
+  pos_ = seek_after_pos;
+
+  *seek_difference = std::max(-(seek_after_pos - seek_previous_pos),
+                              (seek_after_pos - seek_previous_pos));
+
+  return true;
+}
+
+// 読み出し位置を先頭に戻します。
+void reader::FileReader::Begin() {
+  CheckOpened();
+  pos_ = 0;
+  ::rewind(file_pointer_);
+}
+
+// 現在保持している読出し対象のサイズを返します。
+size_t reader::FileReader::GetSize() const {
+  return file_size_;
+}
+
+// 現在の読み出し位置が末尾である場合、trueを返します。
+bool reader::FileReader::IsEof() const {
+  return ::feof(file_pointer_) != 0 || file_size_ == pos_;
+}
+
+// 関数宣言のコメントを参照してください。
+void reader::FileReader::CheckOpened() {
+  if (!IsOpened()) {
+    throw reader::IOException("file isn't open yet! `" + filename_ + "`");
+  }
+}
+
+// 関数宣言のコメントを参照してください。
+void reader::FileReader::CheckEOF() {
+  if (IsEof()) {
+    throw reader::EndOfDeviceException("end of File `" + filename_ + "`");
+  }
+}
+
diff --git a/src/file_reader.h b/src/file_reader.h
new file mode 100755 (executable)
index 0000000..d7423ac
--- /dev/null
@@ -0,0 +1,139 @@
+// 渡されたファイルから1バイト単位での読み出しを行うクラスを定義します。
+// FileReaderは、渡されたファイルからの1バイト単位での読み出し機能を
+// 提供します。
+//
+// example
+// -------
+// FileReader reader("hoge.txt");
+// reader.read(); // == 'h'
+// reader.peek(); // == 'o'
+// reader.read(); // == 'o'
+// reader.read(2); // == "ge"
+//
+// reader.begin(); reader.seek(1, IReader::kForward);
+// reader.read(); // == 'o'
+// reader.read(2);
+// reader.eof(); // == true
+#ifndef _UTAKATA_SRC_FILE_READER_H_
+#define _UTAKATA_SRC_FILE_READER_H_
+
+#include <string>
+#include "src/reader_interface.h"
+#include "src/common/uncopyable.h"
+
+namespace utakata {
+
+namespace reader {
+
+class FileReader : public IReader, private utility::Uncopyable {
+  // 指定されたファイルを開き、データの読出を行います。
+  // 読み出すデータはコンストラクタでのみ指定することができます。
+  // FileReaderのインスタンス1つにつき、1つのファイルが対応します。
+  //
+  // コンストラクタでファイルがオープンされ、デストラクタでクローズ
+  // されます。
+  // 一度Closeされたファイルは、再度明示的にOpenしない限り再度Read
+  // などを行うことはできません。
+  // CloseされているFileReaderに対してRead、Peek、Seekを行うと、
+  // それぞれreader::IOException例外が発生します。
+ public:
+
+  FileReader() : file_pointer_(NULL), filename_(),
+                 pos_(0), file_size_(0) {}
+  explicit FileReader(const std::string& filename)
+      : file_pointer_(NULL), filename_(filename),
+        pos_(0), file_size_(0) {
+    Open();
+  }
+
+  virtual ~FileReader();
+
+  // 現在関連付けられているファイルをOpenします。
+  // すでにオープンされている場合、一度Closeしてから再度開かれます。
+  // 再オープンされた場合、GetPos、GetSizeで返される値は初期化されます。
+  // 正常にファイルをオープンした場合にtrueが返されます。
+  // 正常にファイルがオープンされない場合でも例外は送出されません。
+  bool Open();
+
+  // filenameで指定されたファイルを開きます。
+  // すでにオープンされている場合、前に開かれているファイルをClose
+  // してから、新しいファイルを再度開きます。
+  // 正常にファイルをオープンした場合にtrueが返されます。
+  // 正常にファイルがオープンされない場合でも例外は送出されません。
+  bool Open(const std::string& filename);
+
+  // 現在開いているファイルを閉じます。
+  // ファイルが閉じられている場合、Read、Peek、Seek、Beginを実行すると
+  // 例外が送出されます。
+  void Close();
+
+  // 各種デバイスから一文字読出します。
+  // 末尾に到達してなお読み出しが行われた場合、reader::EndOfDeviceException
+  // 例外を投げなければなりません。
+  // readでは、読み出し位置を更新します。
+  // ファイルがオープンされていない場合には、常に例外が発生します。
+  unsigned char Read();
+  std::vector<unsigned char> Read(size_t num);
+
+  // デバイスから1バイトの読出しを行いますが、内部の読み出し位置は変化
+  // しません。
+  // peekした後、readを行うと、全く同一のバイトが得られます。
+  // ファイルがオープンされていない場合には、常に例外が発生します。
+  unsigned char Peek();
+  std::vector<unsigned char> Peek(size_t num);
+
+  // 現在の読み出し位置を返します。
+  // ファイルがオープンされていない場合、常に0が返されます。
+  size_t GetPos() const;
+
+  // 現在位置から、指定された方向に指定された量だけ読み出し位置を進めます。
+  // 指定された移動量のうち、実際に移動した量を返します。
+  // ファイルがオープンされていない場合には、常に例外が発生します。
+  bool Seek(int seekpos, SeekDirection direciton);
+  bool Seek(int seekpos, SeekDirection direciton, size_t* seek_difference);
+
+  // 読み出し位置を先頭に戻します。
+  // ファイルがオープンされていない場合には、常に例外が発生します。
+  void Begin();
+
+  // 読み出し対象のサイズを返します。
+  // ファイルがオープンされていない場合には、常に0が返されます。
+  size_t GetSize() const;
+
+  // 読み出し位置が末尾であるかどうかを返します。
+  // ファイルがオープンされていない場合には、常にfalseが返されます。
+  bool IsEof() const;
+
+  // FileReaderに関連付けられたファイル名を返します。
+  std::string filename() const {return filename_;}
+
+  // filenameが開かれているか場合、trueを返します。
+  bool IsOpened() const {return file_pointer_ != NULL;}
+
+ private:
+
+  // ファイルの終端であるかどうかのチェックを行い、終端である場合には
+  // 例外を発生させます。
+  void CheckEOF();
+
+  // IsOpened() = trueである場合に、reader::IOExceptionを送出します。
+  void CheckOpened();
+  
+
+  // 読出ファイルへのファイルポインタです。
+  // 常にバイナリ読出("wb")でファイルはオープンされます。
+  FILE* file_pointer_;
+
+  // 関連付けられたファイル名を保持します。
+  std::string filename_;
+
+  // ファイルにおける現在の位置を表します。
+  size_t pos_;
+
+  // 渡されたファイルサイズを取得します。最初に一度だけ初期化されます。
+  size_t file_size_;
+};
+};
+};
+
+#endif /* _UTAKATA_SRC_FILE_READER_H_ */
index 8eb6548..664f4ad 100644 (file)
@@ -32,6 +32,30 @@ class EndOfDeviceException : public std::exception {
   std::string str_;
 };
 
+class IOException : public std::exception {
+  // reader::IReaderインターフェースの派生クラスにおいて、
+  // 入出力に対して発生する例外です。
+ public:
+  // 表示する文字列を渡します。
+  explicit IOException(std::string str) : str_() {
+    const std::string prefix("IOException : ");
+    str_ = prefix + str;
+  }
+
+  virtual ~IOException() throw() {};
+  const char* what() const throw() {
+    return str_.c_str();
+  }
+
+ private:
+
+  std::string str_;
+};
+
+// IReader::Seekの方向を制御します。
+enum SeekDirection {
+  kForward, kBackward,
+};
 
 class IReader {
   // 各種デバイスから読み出しを行うためのインターフェースです。
@@ -41,9 +65,6 @@ class IReader {
 
   virtual ~IReader() {}
 
-  enum SeekDirection {
-    kForward, kBackward,
-  };
 
   // 各種デバイスから一文字読出します。
   // 末尾に到達してなお読み出しが行われた場合、reader::EndOfDeviceException
@@ -61,13 +82,16 @@ class IReader {
   // 読出したバイト数を返します。
   virtual size_t GetPos() const = 0;
 
-  // 読み出し位置を1バイト分だけ戻します。読み出し位置がすでに先頭
-  // である場合でも、例外を発生させる必要はありません。
-  virtual void Unget() = 0;
-
   // 現在位置から、指定された方向に指定された量だけ読み出し位置を進めます。
-  // 指定された移動量のうち、実際に移動した量を返します。
-  virtual size_t Seek(size_t seekpos, SeekDirection direciton) = 0;
+  // 移動に成功したらtrueを返します。
+  virtual bool Seek(int seekpos, SeekDirection direciton) = 0;
+
+  // 現在位置から、指定された方向に指定された量だけ読み出し位置を進め、
+  // 実際に進めた量を返します。
+  // 移動に成功したらtrueを返します。
+  // seek_differenceには、有効なsize_tのポインタを渡す必要があります。
+  virtual bool Seek(int seekpos, SeekDirection direciton,
+                    size_t* seek_difference) = 0;
 
   // 読み出し位置を先頭に戻します。
   virtual void Begin() = 0;
index 7d6c0f6..72756ae 100755 (executable)
 
 namespace reader = utakata::reader;
 
-// 保持している文字列の現在の読み出し位置から1バイト読み出して返します。
-// この関数では、読み出し位置を更新します。
-//
-// IsEofがtrueを返す場合に実行すると、reader::EndOfDeviceExceptionが送出
-// されます。
-// コンストラクタに空文字列が渡されている場合、常に例外を返します。
-unsigned char reader::StringReader::Read()
-{
-  if (iterator_ == buffer_.end()) {
-    throw reader::EndOfDeviceException("end of String `" + buffer_ + "`");
-  }
-
+// 現在位置を示すイテレータの内容を返します。
+unsigned char reader::StringReader::Read() {
+  CheckInternal();
   unsigned char byte = *iterator_++;
   ++pos_;
   return byte;
 }
 
-// 保持している文字列の現在の読み出し位置から指定されたバイト数だけ
-// 読み出して返します。この関数では、読み出し位置を更新します。
-// 指定されたバイト数未満で末尾に到達した場合、読出したデータだけが返されます。
-//
-// IsEofがtrueを返す場合に実行すると、reader::EndOfDeviceExceptionが送出
-// されます。
-// コンストラクタに空文字列が渡されている場合、常に例外を返します。
-//
-// 引数としてゼロ以下の数値が渡された場合、返されるバイト列のサイズは0になります。
+// 読み出しについては、iteratorを利用しています。
 std::vector<unsigned char> reader::StringReader::Read(size_t num) {
+  CheckInternal();
+
   if (num <= 0)
   {
     return std::vector<unsigned char>();
   }
 
-  if (iterator_ == buffer_.end()) {
-    throw reader::EndOfDeviceException("end of String `" + buffer_ + "`");
-  }
-
   std::vector<unsigned char> ret;
   for (size_t i = 0; i < num && iterator_ != buffer_.end(); ++i) {
     ret.push_back(*iterator_++);
@@ -60,31 +41,15 @@ std::vector<unsigned char> reader::StringReader::Read(size_t num) {
   return ret;
 }
 
-// 保持している文字列の現在の読み出し位置から、1バイトだけ
-// 読み出して返します。この関数では、読み出し位置は更新されません。
-// 指定されたバイト数未満で末尾に到達した場合、読出したデータだけが返されます。
-//
-// IsEofがtrueを返す場合に実行すると、reader::EndOfDeviceExceptionが送出
-// されます。
-// コンストラクタに空文字列が渡されている場合、常に例外を返します。
+// イテレータの現在位置の文字を返します。位置は変更しません。
 unsigned char reader::StringReader::Peek() {
-  if (iterator_ == buffer_.end()) {
-    throw reader::EndOfDeviceException("end of String `" + buffer_ + "`");
-  }
-
+  CheckInternal();
   return *iterator_;
 }
 
-// 保持している文字列の現在の読み出し位置から、指定されたバイト数だけ
-// 読み出して返します。この関数では、読み出し位置は更新されません。
-// 指定されたバイト数未満で末尾に到達した場合、読出したデータだけが返されます。
-//
-// IsEofがtrueを返す場合に実行すると、reader::EndOfDeviceExceptionが送出
-// されます。
-// コンストラクタに空文字列が渡されている場合、常に例外を返します。
-//
-// 引数としてゼロ以下の値が渡された場合、返り値のサイズは0となります。
+// 現在のイテレータのコピーを作成し、numだけ進めながら文字を取得します。
 std::vector<unsigned char> reader::StringReader::Peek(size_t num) {
+  CheckInternal();
   if (num <= 0) {
     return std::vector<unsigned char>();
   }
@@ -107,44 +72,61 @@ size_t reader::StringReader::GetPos() const {
   return pos_;
 }
 
-// 読み出し位置を1バイト分だけ戻します。
-// 先頭で実行された場合には何も行いません。
-void reader::StringReader::Unget() {
-  if (iterator_ != buffer_.begin()) {
-    --iterator_;
-    --pos_;
+// seekposにゼロ以下の値が渡された場合、失敗と判定されます。
+bool reader::StringReader::Seek(
+    int seekpos, reader::SeekDirection direction) {
+  CheckInternal();
+
+  if (seekpos <= 0) {
+    return false;
+  }
+
+  if (direction == reader::kForward) {
+    for (int i = 0; i < seekpos && iterator_ != buffer_.end();
+         ++i, ++pos_, ++iterator_) {}
+    if (pos_ >= buffer_.size()) {
+      pos_ = buffer_.size();
+    }
+
+  } else {
+    for (int i = 0; i < seekpos && iterator_ != buffer_.begin();
+         ++i, --pos_, --iterator_) {}
+    if (pos_ <= 0) {
+      pos_ = 0;
+    }
   }
+
+  return true;
 }
 
-// 読み出し位置を、指定された方向に指定された量だけ移動します。
-// 移動量が、先頭、または末尾を超えた場合、それぞれ先頭、末尾に
-// 位置します。
-// seekpos以下の値で、移動した量を返します。
-//
-// seekposにゼロ以下の値が渡された場合、何も行いません。
-size_t reader::StringReader::Seek(
-    size_t seekpos, reader::StringReader::SeekDirection direction) {
+// seek_differenceには、移動した量だけが返されます。
+bool reader::StringReader::Seek(int seekpos,
+                                reader::SeekDirection direction,
+                                size_t* seek_difference) {
   if (seekpos <= 0) {
-    return 0;
+    return false;
   }
 
   int count = 0;
-  if (direction == reader::IReader::kForward) {
-    for (size_t i = 0; i < seekpos && iterator_ != buffer_.end();
+  if (direction == reader::kForward) {
+
+    for (int i = 0; i < seekpos && iterator_ != buffer_.end();
          ++i, ++pos_, ++iterator_, ++count) {}
-    if (pos_ > buffer_.size()) {
+    if (pos_ >= buffer_.size()) {
+      count -= pos_ - buffer_.size();
       pos_ = buffer_.size();
     }
-
   } else {
-    for (size_t i = 0; i < seekpos && iterator_ != buffer_.begin();
+    for (int i = 0; i < seekpos && iterator_ != buffer_.begin();
          ++i, --pos_, --iterator_, ++count) {}
-    if (pos_ < 0) {
+    if (pos_ <= 0) {
+      count += pos_;
       pos_ = 0;
     }
   }
+  *seek_difference = count;
 
-  return count;
+  return true;
 }
 
 // 読み出し位置を先頭に戻します。
@@ -162,3 +144,9 @@ size_t reader::StringReader::GetSize() const {
 bool reader::StringReader::IsEof() const {
   return iterator_ == buffer_.end();
 }
+
+void reader::StringReader::CheckInternal() {
+  if (iterator_ == buffer_.end()) {
+    throw reader::EndOfDeviceException("end of String `" + buffer_ + "`");
+  }
+}
index 673965a..8feeed7 100644 (file)
@@ -56,13 +56,12 @@ class StringReader : public IReader, private utility::Uncopyable {
   // 現在の読み出し位置を返します。
   size_t GetPos() const;
 
-  // 読み出し位置を1バイト分だけ戻します。読み出し位置がすでに先頭
-  // である場合でも、例外を発生させる必要はありません。
-  void Unget();
-
   // 現在位置から、指定された方向に指定された量だけ読み出し位置を進めます。
-  // 指定された移動量のうち、実際に移動した量を返します。
-  size_t Seek(size_t seekpos, SeekDirection direciton);
+  // 正しく移動できた場合、trueを返します。
+  // seek_differenceには、実際に移動した量を設定するため、有効であるポインタ
+  // を渡さなければなりません。
+  bool Seek(int seekpos, SeekDirection direciton);
+  bool Seek(int seekpos, SeekDirection direciton, size_t* seek_difference);
 
   // 読み出し位置を先頭に戻します。
   void Begin();
@@ -75,6 +74,10 @@ class StringReader : public IReader, private utility::Uncopyable {
 
  private:
 
+  // 内部で利用されます。IsEof = trueである場合に、例外を発生
+  // させます。
+  void CheckInternal();
+
   // 初期化された読出し用の文字列です。内部では書込みなどは行われないため、
   // constです。
   const std::string buffer_;
index 8fac137..4cd3f58 100644 (file)
@@ -30,7 +30,7 @@ POST_INSTALL = :
 NORMAL_UNINSTALL = :
 PRE_UNINSTALL = :
 POST_UNINSTALL = :
-bin_PROGRAMS = string_reader_test$(EXEEXT)
+bin_PROGRAMS = string_reader_test$(EXEEXT) file_reader_test$(EXEEXT)
 subdir = src/test
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -43,6 +43,10 @@ CONFIG_CLEAN_FILES =
 am__installdirs = "$(DESTDIR)$(bindir)"
 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(bin_PROGRAMS)
+am_file_reader_test_OBJECTS = file_reader_test.$(OBJEXT) \
+       file_reader.$(OBJEXT) gtest-all.$(OBJEXT)
+file_reader_test_OBJECTS = $(am_file_reader_test_OBJECTS)
+file_reader_test_LDADD = $(LDADD)
 am_string_reader_test_OBJECTS = string_reader_test.$(OBJEXT) \
        string_reader.$(OBJEXT) gtest-all.$(OBJEXT)
 string_reader_test_OBJECTS = $(am_string_reader_test_OBJECTS)
@@ -55,8 +59,9 @@ CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
 CXXLD = $(CXX)
 CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
        -o $@
-SOURCES = $(string_reader_test_SOURCES)
-DIST_SOURCES = $(string_reader_test_SOURCES)
+SOURCES = $(file_reader_test_SOURCES) $(string_reader_test_SOURCES)
+DIST_SOURCES = $(file_reader_test_SOURCES) \
+       $(string_reader_test_SOURCES)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -177,6 +182,7 @@ LC_ALL = C
 check_PROGRANS = $(bin_PROGRAMS)
 TESTS = $(bin_PROGRAMS)
 string_reader_test_SOURCES = string_reader_test.cpp ../string_reader.cpp gtest/gtest-all.cc
+file_reader_test_SOURCES = file_reader_test.cpp ../file_reader.cpp gtest/gtest-all.cc
 all: all-am
 
 .SUFFIXES:
@@ -233,6 +239,9 @@ uninstall-binPROGRAMS:
 
 clean-binPROGRAMS:
        -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+file_reader_test$(EXEEXT): $(file_reader_test_OBJECTS) $(file_reader_test_DEPENDENCIES) 
+       @rm -f file_reader_test$(EXEEXT)
+       $(CXXLINK) $(file_reader_test_OBJECTS) $(file_reader_test_LDADD) $(LIBS)
 string_reader_test$(EXEEXT): $(string_reader_test_OBJECTS) $(string_reader_test_DEPENDENCIES) 
        @rm -f string_reader_test$(EXEEXT)
        $(CXXLINK) $(string_reader_test_OBJECTS) $(string_reader_test_LDADD) $(LIBS)
@@ -243,6 +252,8 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
+include ./$(DEPDIR)/file_reader.Po
+include ./$(DEPDIR)/file_reader_test.Po
 include ./$(DEPDIR)/gtest-all.Po
 include ./$(DEPDIR)/string_reader.Po
 include ./$(DEPDIR)/string_reader_test.Po
@@ -261,19 +272,19 @@ include ./$(DEPDIR)/string_reader_test.Po
 #      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
 #      $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
-string_reader.o: ../string_reader.cpp
-       $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT string_reader.o -MD -MP -MF $(DEPDIR)/string_reader.Tpo -c -o string_reader.o `test -f '../string_reader.cpp' || echo '$(srcdir)/'`../string_reader.cpp
-       mv -f $(DEPDIR)/string_reader.Tpo $(DEPDIR)/string_reader.Po
-#      source='../string_reader.cpp' object='string_reader.o' libtool=no \
+file_reader.o: ../file_reader.cpp
+       $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT file_reader.o -MD -MP -MF $(DEPDIR)/file_reader.Tpo -c -o file_reader.o `test -f '../file_reader.cpp' || echo '$(srcdir)/'`../file_reader.cpp
+       mv -f $(DEPDIR)/file_reader.Tpo $(DEPDIR)/file_reader.Po
+#      source='../file_reader.cpp' object='file_reader.o' libtool=no \
 #      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
-#      $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o string_reader.o `test -f '../string_reader.cpp' || echo '$(srcdir)/'`../string_reader.cpp
+#      $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o file_reader.o `test -f '../file_reader.cpp' || echo '$(srcdir)/'`../file_reader.cpp
 
-string_reader.obj: ../string_reader.cpp
-       $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT string_reader.obj -MD -MP -MF $(DEPDIR)/string_reader.Tpo -c -o string_reader.obj `if test -f '../string_reader.cpp'; then $(CYGPATH_W) '../string_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../string_reader.cpp'; fi`
-       mv -f $(DEPDIR)/string_reader.Tpo $(DEPDIR)/string_reader.Po
-#      source='../string_reader.cpp' object='string_reader.obj' libtool=no \
+file_reader.obj: ../file_reader.cpp
+       $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT file_reader.obj -MD -MP -MF $(DEPDIR)/file_reader.Tpo -c -o file_reader.obj `if test -f '../file_reader.cpp'; then $(CYGPATH_W) '../file_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../file_reader.cpp'; fi`
+       mv -f $(DEPDIR)/file_reader.Tpo $(DEPDIR)/file_reader.Po
+#      source='../file_reader.cpp' object='file_reader.obj' libtool=no \
 #      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
-#      $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o string_reader.obj `if test -f '../string_reader.cpp'; then $(CYGPATH_W) '../string_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../string_reader.cpp'; fi`
+#      $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o file_reader.obj `if test -f '../file_reader.cpp'; then $(CYGPATH_W) '../file_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../file_reader.cpp'; fi`
 
 gtest-all.o: gtest/gtest-all.cc
        $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gtest-all.o -MD -MP -MF $(DEPDIR)/gtest-all.Tpo -c -o gtest-all.o `test -f 'gtest/gtest-all.cc' || echo '$(srcdir)/'`gtest/gtest-all.cc
@@ -289,6 +300,20 @@ gtest-all.obj: gtest/gtest-all.cc
 #      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
 #      $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gtest-all.obj `if test -f 'gtest/gtest-all.cc'; then $(CYGPATH_W) 'gtest/gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/gtest/gtest-all.cc'; fi`
 
+string_reader.o: ../string_reader.cpp
+       $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT string_reader.o -MD -MP -MF $(DEPDIR)/string_reader.Tpo -c -o string_reader.o `test -f '../string_reader.cpp' || echo '$(srcdir)/'`../string_reader.cpp
+       mv -f $(DEPDIR)/string_reader.Tpo $(DEPDIR)/string_reader.Po
+#      source='../string_reader.cpp' object='string_reader.o' libtool=no \
+#      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
+#      $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o string_reader.o `test -f '../string_reader.cpp' || echo '$(srcdir)/'`../string_reader.cpp
+
+string_reader.obj: ../string_reader.cpp
+       $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT string_reader.obj -MD -MP -MF $(DEPDIR)/string_reader.Tpo -c -o string_reader.obj `if test -f '../string_reader.cpp'; then $(CYGPATH_W) '../string_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../string_reader.cpp'; fi`
+       mv -f $(DEPDIR)/string_reader.Tpo $(DEPDIR)/string_reader.Po
+#      source='../string_reader.cpp' object='string_reader.obj' libtool=no \
+#      DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) \
+#      $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o string_reader.obj `if test -f '../string_reader.cpp'; then $(CYGPATH_W) '../string_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../string_reader.cpp'; fi`
+
 .cpp.o:
        $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
        mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
index a8ab125..cdbc012 100755 (executable)
@@ -5,7 +5,7 @@ SRC_DIR=..
 LC_ALL=C
 # SIBDIRS = . 
 
-bin_PROGRAMS = string_reader_test
+bin_PROGRAMS = string_reader_test file_reader_test
 
 # unicode_test_SOURCES = unicode_test.cpp ${SRC_DIR}/unicode.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/utf8_transcoder.cpp \
 #      ${SRC_DIR}/reader.cpp
@@ -30,3 +30,4 @@ check_PROGRANS = $(bin_PROGRAMS)
 TESTS = $(bin_PROGRAMS)
 
 string_reader_test_SOURCES = string_reader_test.cpp ../string_reader.cpp gtest/gtest-all.cc
+file_reader_test_SOURCES = file_reader_test.cpp ../file_reader.cpp gtest/gtest-all.cc
index 2246cfa..4b5d3c7 100644 (file)
@@ -30,7 +30,7 @@ POST_INSTALL = :
 NORMAL_UNINSTALL = :
 PRE_UNINSTALL = :
 POST_UNINSTALL = :
-bin_PROGRAMS = string_reader_test$(EXEEXT)
+bin_PROGRAMS = string_reader_test$(EXEEXT) file_reader_test$(EXEEXT)
 subdir = src/test
 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -43,6 +43,10 @@ CONFIG_CLEAN_FILES =
 am__installdirs = "$(DESTDIR)$(bindir)"
 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(bin_PROGRAMS)
+am_file_reader_test_OBJECTS = file_reader_test.$(OBJEXT) \
+       file_reader.$(OBJEXT) gtest-all.$(OBJEXT)
+file_reader_test_OBJECTS = $(am_file_reader_test_OBJECTS)
+file_reader_test_LDADD = $(LDADD)
 am_string_reader_test_OBJECTS = string_reader_test.$(OBJEXT) \
        string_reader.$(OBJEXT) gtest-all.$(OBJEXT)
 string_reader_test_OBJECTS = $(am_string_reader_test_OBJECTS)
@@ -55,8 +59,9 @@ CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
 CXXLD = $(CXX)
 CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
        -o $@
-SOURCES = $(string_reader_test_SOURCES)
-DIST_SOURCES = $(string_reader_test_SOURCES)
+SOURCES = $(file_reader_test_SOURCES) $(string_reader_test_SOURCES)
+DIST_SOURCES = $(file_reader_test_SOURCES) \
+       $(string_reader_test_SOURCES)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -177,6 +182,7 @@ LC_ALL = C
 check_PROGRANS = $(bin_PROGRAMS)
 TESTS = $(bin_PROGRAMS)
 string_reader_test_SOURCES = string_reader_test.cpp ../string_reader.cpp gtest/gtest-all.cc
+file_reader_test_SOURCES = file_reader_test.cpp ../file_reader.cpp gtest/gtest-all.cc
 all: all-am
 
 .SUFFIXES:
@@ -233,6 +239,9 @@ uninstall-binPROGRAMS:
 
 clean-binPROGRAMS:
        -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+file_reader_test$(EXEEXT): $(file_reader_test_OBJECTS) $(file_reader_test_DEPENDENCIES) 
+       @rm -f file_reader_test$(EXEEXT)
+       $(CXXLINK) $(file_reader_test_OBJECTS) $(file_reader_test_LDADD) $(LIBS)
 string_reader_test$(EXEEXT): $(string_reader_test_OBJECTS) $(string_reader_test_DEPENDENCIES) 
        @rm -f string_reader_test$(EXEEXT)
        $(CXXLINK) $(string_reader_test_OBJECTS) $(string_reader_test_LDADD) $(LIBS)
@@ -243,6 +252,8 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_reader.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_reader_test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtest-all.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string_reader.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string_reader_test.Po@am__quote@
@@ -261,19 +272,19 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
-string_reader.o: ../string_reader.cpp
-@am__fastdepCXX_TRUE@  $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT string_reader.o -MD -MP -MF $(DEPDIR)/string_reader.Tpo -c -o string_reader.o `test -f '../string_reader.cpp' || echo '$(srcdir)/'`../string_reader.cpp
-@am__fastdepCXX_TRUE@  mv -f $(DEPDIR)/string_reader.Tpo $(DEPDIR)/string_reader.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='../string_reader.cpp' object='string_reader.o' libtool=no @AMDEPBACKSLASH@
+file_reader.o: ../file_reader.cpp
+@am__fastdepCXX_TRUE@  $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT file_reader.o -MD -MP -MF $(DEPDIR)/file_reader.Tpo -c -o file_reader.o `test -f '../file_reader.cpp' || echo '$(srcdir)/'`../file_reader.cpp
+@am__fastdepCXX_TRUE@  mv -f $(DEPDIR)/file_reader.Tpo $(DEPDIR)/file_reader.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='../file_reader.cpp' object='file_reader.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o string_reader.o `test -f '../string_reader.cpp' || echo '$(srcdir)/'`../string_reader.cpp
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o file_reader.o `test -f '../file_reader.cpp' || echo '$(srcdir)/'`../file_reader.cpp
 
-string_reader.obj: ../string_reader.cpp
-@am__fastdepCXX_TRUE@  $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT string_reader.obj -MD -MP -MF $(DEPDIR)/string_reader.Tpo -c -o string_reader.obj `if test -f '../string_reader.cpp'; then $(CYGPATH_W) '../string_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../string_reader.cpp'; fi`
-@am__fastdepCXX_TRUE@  mv -f $(DEPDIR)/string_reader.Tpo $(DEPDIR)/string_reader.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='../string_reader.cpp' object='string_reader.obj' libtool=no @AMDEPBACKSLASH@
+file_reader.obj: ../file_reader.cpp
+@am__fastdepCXX_TRUE@  $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT file_reader.obj -MD -MP -MF $(DEPDIR)/file_reader.Tpo -c -o file_reader.obj `if test -f '../file_reader.cpp'; then $(CYGPATH_W) '../file_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../file_reader.cpp'; fi`
+@am__fastdepCXX_TRUE@  mv -f $(DEPDIR)/file_reader.Tpo $(DEPDIR)/file_reader.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='../file_reader.cpp' object='file_reader.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o string_reader.obj `if test -f '../string_reader.cpp'; then $(CYGPATH_W) '../string_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../string_reader.cpp'; fi`
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o file_reader.obj `if test -f '../file_reader.cpp'; then $(CYGPATH_W) '../file_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../file_reader.cpp'; fi`
 
 gtest-all.o: gtest/gtest-all.cc
 @am__fastdepCXX_TRUE@  $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT gtest-all.o -MD -MP -MF $(DEPDIR)/gtest-all.Tpo -c -o gtest-all.o `test -f 'gtest/gtest-all.cc' || echo '$(srcdir)/'`gtest/gtest-all.cc
@@ -289,6 +300,20 @@ gtest-all.obj: gtest/gtest-all.cc
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o gtest-all.obj `if test -f 'gtest/gtest-all.cc'; then $(CYGPATH_W) 'gtest/gtest-all.cc'; else $(CYGPATH_W) '$(srcdir)/gtest/gtest-all.cc'; fi`
 
+string_reader.o: ../string_reader.cpp
+@am__fastdepCXX_TRUE@  $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT string_reader.o -MD -MP -MF $(DEPDIR)/string_reader.Tpo -c -o string_reader.o `test -f '../string_reader.cpp' || echo '$(srcdir)/'`../string_reader.cpp
+@am__fastdepCXX_TRUE@  mv -f $(DEPDIR)/string_reader.Tpo $(DEPDIR)/string_reader.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='../string_reader.cpp' object='string_reader.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o string_reader.o `test -f '../string_reader.cpp' || echo '$(srcdir)/'`../string_reader.cpp
+
+string_reader.obj: ../string_reader.cpp
+@am__fastdepCXX_TRUE@  $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT string_reader.obj -MD -MP -MF $(DEPDIR)/string_reader.Tpo -c -o string_reader.obj `if test -f '../string_reader.cpp'; then $(CYGPATH_W) '../string_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../string_reader.cpp'; fi`
+@am__fastdepCXX_TRUE@  mv -f $(DEPDIR)/string_reader.Tpo $(DEPDIR)/string_reader.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     source='../string_reader.cpp' object='string_reader.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o string_reader.obj `if test -f '../string_reader.cpp'; then $(CYGPATH_W) '../string_reader.cpp'; else $(CYGPATH_W) '$(srcdir)/../string_reader.cpp'; fi`
+
 .cpp.o:
 @am__fastdepCXX_TRUE@  $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
 @am__fastdepCXX_TRUE@  mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
diff --git a/src/test/file_reader_test.cpp b/src/test/file_reader_test.cpp
new file mode 100755 (executable)
index 0000000..48c3d69
--- /dev/null
@@ -0,0 +1,97 @@
+#include <cstdio>
+#include <gtest/gtest.h>
+#include "src/file_reader.h"
+#include "src/common/scoped_ptr.h"
+
+namespace reader = utakata::reader;
+
+class FileReaderTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    FILE* f = fopen("test.txt", "w");
+    fprintf(f, "%s", "hoge");
+    fclose(f);
+  }
+
+};
+
+TEST_F(FileReaderTest, NormalUsega) {
+  // FileReaderを用いた読み出しを行う。
+  reader::FileReader reader("test.txt");
+
+  EXPECT_EQ(reader.GetSize(), 4);
+
+  EXPECT_EQ(reader.Read(), 'h');
+  EXPECT_EQ(reader.GetPos(), 1);
+
+  EXPECT_EQ(reader.Peek(), 'o');
+  EXPECT_EQ(reader.Read(), 'o');
+  std::vector<unsigned char> t = reader.Read(2);
+  EXPECT_EQ(t[0], 'g');
+  EXPECT_EQ(t[1], 'e');
+
+  EXPECT_EQ(reader.GetPos(), 4);
+  reader.Begin();
+  EXPECT_EQ(reader.GetPos(), 0);
+
+  EXPECT_TRUE(reader.Seek(1, reader::kForward));
+  EXPECT_EQ(reader.Read(), 'o');
+
+  size_t seeksize = 0;
+  EXPECT_TRUE(reader.Seek(1, reader::kBackward, &seeksize));
+  EXPECT_EQ(seeksize, 1);
+  EXPECT_EQ(reader.Read(), 'o');
+
+  t = reader.Read(2);
+  EXPECT_EQ(t[0], 'g');
+  EXPECT_EQ(t[1], 'e');
+  EXPECT_TRUE(reader.IsEof());
+
+  // すでに末尾であるのに進もうとすると例外が発生する。
+  EXPECT_THROW(reader.Read(), reader::EndOfDeviceException);
+}
+
+TEST_F(FileReaderTest, OpenAndClose) {
+  reader::FileReader reader("test.txt");
+
+  EXPECT_EQ(reader.GetSize(), 4);
+
+  EXPECT_EQ(reader.Read(), 'h');
+  EXPECT_EQ(reader.GetPos(), 1);
+
+  EXPECT_EQ(reader.Peek(), 'o');
+  EXPECT_EQ(reader.Read(), 'o');
+  std::vector<unsigned char> t = reader.Read(2);
+  EXPECT_EQ(t[0], 'g');
+  EXPECT_EQ(t[1], 'e');
+
+  EXPECT_EQ(reader.GetPos(), 4);
+
+  reader.Close();
+
+  EXPECT_THROW(reader.Read(), reader::IOException);
+  reader.Open();
+
+  EXPECT_TRUE(reader.Seek(1, reader::kForward));
+  EXPECT_EQ(reader.Read(), 'o');
+
+  size_t seeksize = 0;
+  EXPECT_TRUE(reader.Seek(1, reader::kBackward, &seeksize));
+  EXPECT_EQ(seeksize, 1);
+  EXPECT_EQ(reader.Read(), 'o');
+
+  t = reader.Read(2);
+  EXPECT_EQ(t[0], 'g');
+  EXPECT_EQ(t[1], 'e');
+  EXPECT_TRUE(reader.IsEof());
+
+  // すでに末尾であるのに進もうとすると例外が発生する。
+  EXPECT_THROW(reader.Read(), reader::EndOfDeviceException);
+}
+
+int main(int argc, char** argv)
+{
+  testing::InitGoogleTest(&argc, argv);
+
+  return RUN_ALL_TESTS();
+}
index 91f66d2..bbd093b 100644 (file)
@@ -22,10 +22,12 @@ TEST(StringReaderTest, Test1) {
   reader.Begin();
   EXPECT_EQ(reader.GetPos(), 0);
 
-  EXPECT_EQ(reader.Seek(1, reader::StringReader::kForward), 1);
+  EXPECT_TRUE(reader.Seek(1, reader::kForward));
   EXPECT_EQ(reader.Read(), 'o');
 
-  EXPECT_EQ(reader.Seek(1, reader::StringReader::kBackward), 1);
+  size_t seeksize = 0;
+  EXPECT_TRUE(reader.Seek(1, reader::kBackward, &seeksize));
+  EXPECT_EQ(seeksize, 1);
   EXPECT_EQ(reader.Read(), 'o');
 
   t = reader.Read(2);
@@ -33,10 +35,6 @@ TEST(StringReaderTest, Test1) {
   EXPECT_EQ(t[1], 'e');
   EXPECT_TRUE(reader.IsEof());
 
-  reader.Unget();
-  EXPECT_FALSE(reader.IsEof());
-  EXPECT_EQ(reader.Read(), 'e');
-
   // すでに末尾であるのに進もうとすると例外が発生する。
   EXPECT_THROW(reader.Read(), reader::EndOfDeviceException);
 }