///////////////////////////////////////////////////////////////////////////////
//
//   単純なファイルストリーム


#ifndef FSTREAM_H
#define FSTREAM_H


#include "stream.h"
#include "filedesc.h"


///////////////////////////////////////////////////////////////////////////////

#define BAD_ALLOC() do { } while(0)
#define NULL_POINTER_EXCEPTION() do {} while(0)



///////////////////////////////////////////////////////////////////////////////

class FileInputStream: public InputStream {
  FileDescriptor *file_;

public:
  //===========================================================================
  /*! コンストラクタ
   * @param fname  ファイル名
   * @param ex    ファイルが存在する場合の挙動
   * @param ne    ファイルが存在しない場合の挙動
   */
  FileInputStream(const char *fname,
                   FileDescriptor::IfExists ex,
                   FileDescriptor::IfNotExists ne )
  {
    try {
      file_ = new FileDescriptor(fname, FileDescriptor::mdREAD, ex, ne );
      if (!file_) BAD_ALLOC();
    } catch(...) {
      file_ = 0;
      throw;
    }
  }

  //===========================================================================
  //! デストラクタ
  ~FileInputStream() {
    delete file_;
  }

  //===========================================================================
  //! ファイルを読む
  unsigned long read(void *buf, unsigned long size) {
    if (! file_) {
      NULL_POINTER_EXCEPTION();
      return 0;
    }

    return file_->read(buf, size);
  }

  //===========================================================================
  /*! ファイルハンドルを得る
   * FileDescriptor クラスや FileInputStream クラスでサポートしていない API を
   * 呼び出すために使う
   */
  FileHandle getHandle() {
    if (!file_) {
      NULL_POINTER_EXCEPTION();
      return 0;
    }

    return file_->getHandle();
  }
};


///////////////////////////////////////////////////////////////////////////////

/*! ファイルに書き込む
 */
class FileOutputStream : public OutputStream {

  FileDescriptor *file_;

public:

  //===========================================================================
  /*! コンストラクタ
   * @param fname ファイル名
   * @param ex ファイルが存在する場合の挙動
   * @param ne ファイルが存在しない場合の挙動
   */
  FileOutputStream(const char *fname,
                   FileDescriptor::IfExists ex,
                   FileDescriptor::IfNotExists ne)
  {
    try {
      file_ = new FileDescriptor(fname, FileDescriptor::mdWRITE, ex, ne);
      if (!file_) BAD_ALLOC();
    } catch(...) {
      file_ = 0;
      throw;
    }
  }


  //===========================================================================
  //! デストラクタ
  ~FileOutputStream() {
    delete file_;
  }


  //===========================================================================
  //! ファイルに書き込み
  unsigned long write(const void *buf, unsigned long size ) {
    if (! file_) {
      NULL_POINTER_EXCEPTION();
      return 0;
    }

    return file_->write(buf, size);
  }

  //===========================================================================
  /*! ファイルハンドルを得る
   * ファイルハンドルを使う API を呼び出すために使う
   * 中身は HANDLE 型だったり FILE * 型だったり <- FileDescriptor の実装による
   */
  FileHandle getHandle() {
    if (! file_) {
      NULL_POINTER_EXCEPTION();
      return 0;
    }

    return file_->getHandle();
  }
};

#undef BAD_ALLOC
#undef NULL_POINTER_EXCEPTION


#endif // FSTREAM_H


