/*
 * Written by Masayuki Takigahira
 * Copyright 2012 Kyoto University and Honda Motor Co.,Ltd.
 * All rights reserved.
 * HARK was developed by researchers in Okuno Laboratory
 * at the Kyoto University and Honda Research Institute Japan Co.,Ltd.
 */

/*
#include <iostream>
#include <BufferedNode.h>
#include <Buffer.h>
#include <Vector.h>
#include <Matrix.h>
#include <Source.h>
#include <Map.h>
#include <TimeStamp.h>
#include <Stream.h>
#include <math.h>

#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
*/

#ifndef HARK_FLAC_BASE_HPP
#define HARK_FLAC_BASE_HPP

//include c headers
#include <cstdio>
#include <cstdlib> /* for size_t, malloc(), etc */
#include <cstring>
#include <climits> /* for SIZE_MAX */

#include <unistd.h>

////#include <pthread.h>

//include c++ headers
#include <string>

#include <iomanip>

//include common in flac library headers
//#include "share/compat.h"
//#include "share/alloc.h" //already implemented the necessary part.

//include flac headers
//#include "FLAC/assert.h" //already implemented the necessary part.
#include "FLAC/stream_encoder.h"
#include "FLAC/stream_decoder.h"
#include "FLAC/metadata.h"


#if HAVE_CONFIG_H
  #include <config.h>
#endif

//This is implementation different from the "share/alloc.h" in flac library, but it works just fine usually.
#ifndef SIZE_MAX
  #ifndef SIZE_T_MAX
    #define SIZE_T_MAX ((size_t) -1)
  #endif //!SIZE_T_MAX
  #define SIZE_MAX SIZE_T_MAX
#endif //!SIZE_MAX

#define HARK_FLAC_DEBUG_MODE 1
//#undef HARK_FLAC_DEBUG_MODE

// assert() for Debug FLAC processing.
#ifdef HARK_FLAC_DEBUG_MODE
  #include <assert.h>
  #define HARK_ASSERT(x) assert(x)
#else
  #define HARK_ASSERT(x)
#endif

#ifdef _MSC_VER
  // warning C4800: 'int' : forcing to bool 'true' or 'false' (performance warning)
  #pragma warning ( disable : 4800 )
#endif

// This code is pure libFLAC wrapper. And this code is Xiph.org (BSD-like) license for refered from libFLAC++.
// Added class and methods for following HARK fnctions. Removed virtual keyword except callbacks for performance.
// FLAC callback functions difficult to use for HARK, because HARK cannot processing event driven.
// Support stream encoding, decoding multi source request from HARK, and support response finish each source to HARK.

#ifdef PUBLISHER // bad work, will fix later.
  namespace HARKPF {
#else
  namespace HARKSF {
#endif

namespace HARK_FLAC {
  // avoid malloc()ing 0 bytes, see: https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003
  // revised code by takigahira, see: https://www.securecoding.cert.org/confluence/display/seccode/MEM04-C.+Beware+of+zero-length+allocations
  static inline void *safe_malloc_(size_t size) //safety code of std::malloc(size)
  {
    //if(!size){ size++; } // malloc(0) is undefined; FLAC src convention is to always allocate
    if(!size){ return 0; } // I think a mistake to allocate of memory. by takigahira.
    return std::malloc(size);
  }
  static inline void *safe_calloc_(size_t nmemb, size_t size) //safety code of std::calloc(nmemb,size)
  {
    //if(!nmemb || !size){ return malloc(1); } // malloc(0) is undefined; FLAC src convention is to always allocate
    if(!nmemb || !size){ return 0; } // I think a mistake to allocate of memory. by takigahira.
    return std::calloc(nmemb, size);
  }
  static inline void *safe_malloc_add_2op_(size_t size1, size_t size2) //safety code of std::malloc(size1+size2)
  {
    size2 += size1; if(size2 < size1){ return 0; }
    return safe_malloc_(size2);
  }
  static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3) //safety code of std::malloc(size1+size2+size3)
  {
    size2 += size1; if(size2 < size1){ return 0; }
    size3 += size2; if(size3 < size2){ return 0; }
    return safe_malloc_(size3);
  }
  static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4) //safety code of std::malloc(size1+size2+size3+size4)
  {
    size2 += size1; if(size2 < size1){ return 0; }
    size3 += size2; if(size3 < size2){ return 0; }
    size4 += size3; if(size4 < size3){ return 0; }
    return safe_malloc_(size4);
  }
  void *safe_malloc_mul_2op_(size_t size1, size_t size2);
  static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3) //safety code of std::malloc(size1*size2*size3)
  {
    //if(!size1 || !size2 || !size3){ return malloc(1); } // malloc(0) is undefined; FLAC src convention is to always allocate
    if(!size1 || !size2 || !size3){ return 0; } // I think a mistake to allocate of memory. by takigahira.
    if(size1 > SIZE_MAX / size2){ return 0; }
    size1 *= size2; if(size1 > SIZE_MAX / size3){ return 0; }
    return std::malloc(size1*size3);
  }
  static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3) //safety code of std::malloc(size1*size2+size3)
  {
    if(!size1 || !size2){ return safe_malloc_(size3); }
    if(size1 > SIZE_MAX / size2){ return 0; }
    return safe_malloc_add_2op_(size1*size2, size3);
  }
  static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3) //safety code of std::malloc(size1*(size2+size3))
  {
    //if(!size1 || (!size2 && !size3)){ return malloc(1); } // malloc(0) is undefined; FLAC src convention is to always allocate
    if(!size1 || (!size2 && !size3)){ return 0; } // I think a mistake to allocate of memory. by takigahira.
    size2 += size3; if(size2 < size3){ return 0; }
    if(size1 > SIZE_MAX / size2){ return 0; }
    return std::malloc(size1*size2);
  }
  static inline void *safe_realloc_(void *ptr, size_t size) //safety code of std::realloc(ptr,size)
  {
    if(!size){ std::free(ptr); ptr = 0; return 0; } // I think an undesirable to hold allocation address of memory. by takigahira.
    return std::realloc(ptr, size);
  }
  static inline void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2) //safety code of std::realloc(ptr,size1+size2)
  {
    size2 += size1; if(size2 < size1){ return 0; }
    //return std::realloc(ptr, size2);
    return safe_realloc_(ptr, size2); // I think an undesirable to hold allocation address of memory. by takigahira.
  }
  static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) //safety code of std::realloc(ptr,size1+size2+size3)
  {
    size2 += size1; if(size2 < size1){ return 0; }
    size3 += size2; if(size3 < size2){ return 0; }
    //return std::realloc(ptr, size3);
    return safe_realloc_(ptr, size3); // I think an undesirable to hold allocation address of memory. by takigahira.
  }
  static inline void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) //safety code of std::realloc(ptr,size1+size2+size3+size4)
  {
    size2 += size1; if(size2 < size1){ return 0; }
    size3 += size2; if(size3 < size2){ return 0; }
    size4 += size3; if(size4 < size3){ return 0; }
    //return std::realloc(ptr, size4);
    return safe_realloc_(ptr, size4); // I think an undesirable to hold allocation address of memory. by takigahira.
  }
  static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2) //safety code of std::realloc(ptr,size1*size2)
  {
    //if(!size1 || !size2){ return realloc(ptr, 0); } // preserve POSIX realloc(ptr, 0) semantics
    if(!size1 || !size2){ std::free(ptr); ptr = 0; return 0; } // I think an undesirable to hold allocation address of memory. by takigahira.
    if(size1 > SIZE_MAX / size2){ return 0; }
    return std::realloc(ptr, size1*size2);
  }
  static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) //safety code of std::realloc(ptr,size1*(size2+size3))
  {
    //if(!size1 || (!size2 && !size3)){ return realloc(ptr, 0); } // preserve POSIX realloc(ptr, 0) semantics
    if(!size1 || (!size2 && !size3)){ std::free(ptr); ptr = 0; return 0; } // I think an undesirable to hold allocation address of memory. by takigahira.
    size2 += size3; if(size2 < size3){ return 0; }
    return safe_realloc_mul_2op_(ptr, size1, size2);
  }
  
  namespace Metadata {
    class Prototype {
    protected:
      //Constructor
      Prototype(const Prototype &object): hark_metadata_object(::FLAC__metadata_object_clone(object.hark_metadata_object)), is_reference_flag(false)
      {
        HARK_ASSERT(object.is_valid());
      }
      Prototype(const ::FLAC__StreamMetadata &object): hark_metadata_object(::FLAC__metadata_object_clone(&object)), is_reference_flag(false)
      {
      }
      Prototype(const ::FLAC__StreamMetadata *object): hark_metadata_object(::FLAC__metadata_object_clone(object)), is_reference_flag(false)
      {
        HARK_ASSERT(0 != object);
      }
      
      //Copy Constructor
      Prototype(::FLAC__StreamMetadata *object, bool copy): hark_metadata_object(copy? ::FLAC__metadata_object_clone(object) : object), is_reference_flag(false)
      {
        HARK_ASSERT(0 != object);
      }
      
      //Operator
      Prototype &operator=(const Prototype &object)
      {
        HARK_ASSERT(object.is_valid());
        clear();
        is_reference_flag = false;
        hark_metadata_object = ::FLAC__metadata_object_clone(object.hark_metadata_object);
        return *this;
      }
      Prototype &operator=(const ::FLAC__StreamMetadata &object)
      {
        clear();
        is_reference_flag = false;
        hark_metadata_object = ::FLAC__metadata_object_clone(&object);
        return *this;
      }
      Prototype &operator=(const ::FLAC__StreamMetadata *object)
      {
        HARK_ASSERT(0 != object);
        clear();
        is_reference_flag = false;
        hark_metadata_object = ::FLAC__metadata_object_clone(object);
        return *this;
      }
      Prototype &assign_object(::FLAC__StreamMetadata *object, bool copy)
      {
        HARK_ASSERT(0 != object);
        clear();
        hark_metadata_object = (copy ? ::FLAC__metadata_object_clone(object) : object);
        is_reference_flag = false;
        return *this;
      }
      void clear()
      {
        if(0 != hark_metadata_object && !is_reference_flag){ FLAC__metadata_object_delete(hark_metadata_object); }
        hark_metadata_object = 0;
      }
      ::FLAC__StreamMetadata *hark_metadata_object;
      
    public:
      //Destructor
      virtual ~Prototype(){ clear(); } //Since this class is the premise that is inherited, I put the "virtual" keyword.
      
      //Operator
      inline bool operator==(const Prototype &object) const{ return (bool) ::FLAC__metadata_object_is_equal(hark_metadata_object, object.hark_metadata_object); }
      inline bool operator==(const ::FLAC__StreamMetadata &object) const{ return (bool) ::FLAC__metadata_object_is_equal(hark_metadata_object, &object); }
      inline bool operator==(const ::FLAC__StreamMetadata *object) const{ return (bool) ::FLAC__metadata_object_is_equal(hark_metadata_object, object); }
      inline bool operator!=(const Prototype &object) const{ return !operator==(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata &object) const{ return !operator==(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata *object) const{ return !operator==(object); }
      friend class SimpleIterator;
      friend class Iterator;
      inline bool is_valid() const{ return 0 != hark_metadata_object; }
      
      //Getter
      bool get_is_last() const
      {
        HARK_ASSERT(is_valid());
        return (bool) hark_metadata_object->is_last;
      }
      ::FLAC__MetadataType get_type() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->type;
      }
      unsigned get_length() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->length;
      }
      
      //Setter
      void set_is_last(bool value)
      {
        HARK_ASSERT(is_valid());
        hark_metadata_object->is_last = value;
      }
      inline operator const ::FLAC__StreamMetadata *() const;
      
    private:
      Prototype();
      bool is_reference_flag;
      inline void set_reference(bool x){ is_reference_flag = x; }
      
    }; // [HARK_FLAC::Metadata::Prototype] class Prototype is end
    class StreamInfo: public Prototype {
    public:
      //Constructor
      StreamInfo(): Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO), /*copy=*/false){ }
      
      inline StreamInfo(const StreamInfo &object): Prototype(object) { }
      inline StreamInfo(const ::FLAC__StreamMetadata &object): Prototype(object) { }
      inline StreamInfo(const ::FLAC__StreamMetadata *object): Prototype(object) { }
      
      inline StreamInfo(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
      
      //Destructor
      ~StreamInfo(){ }
      
      //Operator
      inline StreamInfo &operator=(const StreamInfo &object) { Prototype::operator=(object); return *this; }
      inline StreamInfo &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
      inline StreamInfo &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
      
      inline StreamInfo &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
      
      inline bool operator==(const StreamInfo &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
      
      inline bool operator!=(const StreamInfo &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
      
      //Getter
      unsigned get_min_blocksize() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.stream_info.min_blocksize;
      }
      unsigned get_max_blocksize() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.stream_info.max_blocksize;
      }
      unsigned get_min_framesize() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.stream_info.min_framesize;
      }
      unsigned get_max_framesize() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.stream_info.max_framesize;
      }
      unsigned get_sample_rate() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.stream_info.sample_rate;
      }
      unsigned get_channels() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.stream_info.channels;
      }
      unsigned get_bits_per_sample() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.stream_info.bits_per_sample;
      }
      FLAC__uint64 get_total_samples() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.stream_info.total_samples;
      }
      const FLAC__byte *get_md5sum() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.stream_info.md5sum;
      }
      
      //Setter
      void set_min_blocksize(unsigned value)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
        HARK_ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
        hark_metadata_object->data.stream_info.min_blocksize = value;
      }
      void set_max_blocksize(unsigned value)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(value >= FLAC__MIN_BLOCK_SIZE);
        HARK_ASSERT(value <= FLAC__MAX_BLOCK_SIZE);
        hark_metadata_object->data.stream_info.max_blocksize = value;
      }
      void set_min_framesize(unsigned value)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
        hark_metadata_object->data.stream_info.min_framesize = value;
      }
      void set_max_framesize(unsigned value)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(value < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
        hark_metadata_object->data.stream_info.max_framesize = value;
      }
      void set_sample_rate(unsigned value)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(FLAC__format_sample_rate_is_valid(value));
        hark_metadata_object->data.stream_info.sample_rate = value;
      }
      void set_channels(unsigned value)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(value > 0);
        HARK_ASSERT(value <= FLAC__MAX_CHANNELS);
        hark_metadata_object->data.stream_info.channels = value;
      }
      void set_bits_per_sample(unsigned value)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(value >= FLAC__MIN_BITS_PER_SAMPLE);
        HARK_ASSERT(value <= FLAC__MAX_BITS_PER_SAMPLE);
        hark_metadata_object->data.stream_info.bits_per_sample = value;
      }
      void set_total_samples(FLAC__uint64 value)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(value < (((FLAC__uint64)1) << FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN));
        hark_metadata_object->data.stream_info.total_samples = value;
      }
      void set_md5sum(const FLAC__byte value[16])
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(0 != value);
        std::memcpy(hark_metadata_object->data.stream_info.md5sum, value, 16);
      }
      
    }; // [HARK_FLAC::Metadata::StreamInfo] class StreamInfo is end
    class Padding: public Prototype {
    public:
      //Constructor
      Padding(): Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false){ }
      
      Padding(unsigned length): Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING), /*copy=*/false){ set_length(length); }
      
      inline Padding(const Padding &object): Prototype(object){ }
      inline Padding(const ::FLAC__StreamMetadata &object): Prototype(object){ }
      inline Padding(const ::FLAC__StreamMetadata *object): Prototype(object){ }
      
      inline Padding(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy){ }
      
      //Destructor
      ~Padding(){ }
      
      //Operator
      inline Padding &operator=(const Padding &object) { Prototype::operator=(object); return *this; }
      inline Padding &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
      inline Padding &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
      
      inline Padding &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
      
      inline bool operator==(const Padding &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
      
      inline bool operator!=(const Padding &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
      
      //Setter
      void set_length(unsigned length)
      {
        HARK_ASSERT(is_valid());
        hark_metadata_object->length = length;
      }
      
    }; // [HARK_FLAC::Metadata::Padding] class Padding is end
    class Application: public Prototype {
    public:
      //Constructor
      Application(): Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false){ }
      
      inline Application(const Application &object): Prototype(object){ }
      inline Application(const ::FLAC__StreamMetadata &object): Prototype(object){ }
      inline Application(const ::FLAC__StreamMetadata *object): Prototype(object){ }
      
      inline Application(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy){ }
      
      //Destructor
      ~Application(){ }
      
      //Operator
      inline Application &operator=(const Application &object) { Prototype::operator=(object); return *this; }
      inline Application &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
      inline Application &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
      
      inline Application &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
      
      inline bool operator==(const Application &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
      
      inline bool operator!=(const Application &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
      
      //Getter
      const FLAC__byte *get_id() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.application.id;
      }
      const FLAC__byte *get_data() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.application.data;
      }
      
      //Setter
      void set_id(const FLAC__byte value[4])
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(0 != value);
        std::memcpy(hark_metadata_object->data.application.id, value, 4);
      }
      bool set_data(const FLAC__byte *data, unsigned length)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_application_set_data(hark_metadata_object, (FLAC__byte*)data, length, true);
      }
      bool set_data(FLAC__byte *data, unsigned length, bool copy)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_application_set_data(hark_metadata_object, data, length, copy);
      }
      
    }; // [HARK_FLAC::Metadata::Application] class Application is end
    class SeekTable: public Prototype {
    public:
      //Constructor
      SeekTable(): Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE), /*copy=*/false){ }
      
      inline SeekTable(const SeekTable &object): Prototype(object){ }
      inline SeekTable(const ::FLAC__StreamMetadata &object): Prototype(object){ }
      inline SeekTable(const ::FLAC__StreamMetadata *object): Prototype(object){ }
      
      inline SeekTable(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy){ }
      
      //Destructor
      ~SeekTable(){ }
      
      inline SeekTable &operator=(const SeekTable &object) { Prototype::operator=(object); return *this; }
      inline SeekTable &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
      inline SeekTable &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
      
      inline SeekTable &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
      
      //Operator
      inline bool operator==(const SeekTable &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
      
      inline bool operator!=(const SeekTable &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
      
      //Getter
      unsigned get_num_points() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.seek_table.num_points;
      }
      ::FLAC__StreamMetadata_SeekPoint get_point(unsigned index) const
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(index < hark_metadata_object->data.seek_table.num_points);
        return hark_metadata_object->data.seek_table.points[index];
      }
      
      //Setter
      bool resize_points(unsigned new_num_points)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_seektable_resize_points(hark_metadata_object, new_num_points);
      }
      void set_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(index < hark_metadata_object->data.seek_table.num_points);
        ::FLAC__metadata_object_seektable_set_point(hark_metadata_object, index, point);
      }
      bool insert_point(unsigned index, const ::FLAC__StreamMetadata_SeekPoint &point)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(index <= hark_metadata_object->data.seek_table.num_points);
        return (bool) ::FLAC__metadata_object_seektable_insert_point(hark_metadata_object, index, point);
      }
      bool delete_point(unsigned index)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(index < hark_metadata_object->data.seek_table.num_points);
        return (bool) ::FLAC__metadata_object_seektable_delete_point(hark_metadata_object, index);
      }
      bool is_legal() const
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_seektable_is_legal(hark_metadata_object);
      }
      bool template_append_placeholders(unsigned num)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_seektable_template_append_placeholders(hark_metadata_object, num);
      }
      bool template_append_point(FLAC__uint64 sample_number)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_seektable_template_append_point(hark_metadata_object, sample_number);
      }
      bool template_append_points(FLAC__uint64 sample_numbers[], unsigned num)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_seektable_template_append_points(hark_metadata_object, sample_numbers, num);
      }
      bool template_append_spaced_points(unsigned num, FLAC__uint64 total_samples)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_seektable_template_append_spaced_points(hark_metadata_object, num, total_samples);
      }
      bool template_append_spaced_points_by_samples(unsigned samples, FLAC__uint64 total_samples)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(hark_metadata_object, samples, total_samples);
      }
      bool template_sort(bool compact)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_seektable_template_sort(hark_metadata_object, compact);
      }
      
    }; // [HARK_FLAC::Metadata::SeekTable] class SeekTable is end
    class VorbisComment: public Prototype {
    public:
      class Entry {
      public:
        //Constructor
        Entry()
        {
          zero();
        }
        
        Entry(const char *field, unsigned field_length)
        {
          zero();
          construct(field, field_length);
        }
        Entry(const char *field) // assumes \a field is NUL-terminated
        {
          zero();
          construct(field);
        }
        
        Entry(const char *field_name, const char *field_value, unsigned field_value_length)
        {
          zero();
          construct(field_name, field_value, field_value_length);
        }
        Entry(const char *field_name, const char *field_value) // assumes \a field_value is NUL-terminated
        {
          zero();
          construct(field_name, field_value);
        }
        
        Entry(const Entry &entry)
        {
          HARK_ASSERT(entry.is_valid());
          zero();
          construct((const char *)entry.entry_.entry, entry.entry_.length);
        }
        
        Entry &operator=(const Entry &entry)
        {
          HARK_ASSERT(entry.is_valid());
          clear();
          construct((const char *)entry.entry_.entry, entry.entry_.length);
          return *this;
        }
        
        //Destructor
        virtual ~Entry()
        {
          clear();
        }
        
        virtual bool is_valid() const ///< Returns \c true iff object was properly constructed.
        {
          return is_valid_;
        }
        
        //Getter
        unsigned get_field_length() const
        {
          HARK_ASSERT(is_valid());
          return entry_.length;
        }
        unsigned get_field_name_length() const
        {
          HARK_ASSERT(is_valid());
          return field_name_length_;
        }
        unsigned get_field_value_length() const
        {
          HARK_ASSERT(is_valid());
          return field_value_length_;
        }
        
        ::FLAC__StreamMetadata_VorbisComment_Entry get_entry() const
        {
          HARK_ASSERT(is_valid());
          return entry_;
        }
        const char *get_field() const
        {
          HARK_ASSERT(is_valid());
          return (const char *)entry_.entry;
        }
        const char *get_field_name() const
        {
          HARK_ASSERT(is_valid());
          return field_name_;
        }
        const char *get_field_value() const
        {
          HARK_ASSERT(is_valid());
          return field_value_;
        }
        
        //Setter
        bool set_field(const char *field, unsigned field_length)
        {
          HARK_ASSERT(is_valid());
          HARK_ASSERT(0 != field);
          
          if(!::FLAC__format_vorbiscomment_entry_is_legal((const ::FLAC__byte*)field, field_length)){
            return is_valid_ = false;
          }
          
          clear_entry();
          
          if(0 == (entry_.entry = (FLAC__byte*)safe_malloc_add_2op_(field_length, /*+*/1))){
            is_valid_ = false;
          }
          else{
            entry_.length = field_length;
            std::memcpy(entry_.entry, field, field_length);
            entry_.entry[field_length] = '\0';
            (void) parse_field();
          }
          
          return is_valid_;
        }
        bool set_field(const char *field) // assumes \a field is NUL-terminated
        {
          return set_field(field, strlen(field));
        }
        bool set_field_name(const char *field_name)
        {
          HARK_ASSERT(is_valid());
          HARK_ASSERT(0 != field_name);
          
          if(!::FLAC__format_vorbiscomment_entry_name_is_legal(field_name)){
            return is_valid_ = false;
          }
          
          clear_field_name();
          
          if(0 == (field_name_ = strdup(field_name))){
            is_valid_ = false;
          }
          else{
            field_name_length_ = strlen(field_name_);
            compose_field();
          }
          
          return is_valid_;
        }
        bool set_field_value(const char *field_value, unsigned field_value_length)
        {
          HARK_ASSERT(is_valid());
          HARK_ASSERT(0 != field_value);
          
          if(!::FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte*)field_value, field_value_length)){
            return is_valid_ = false;
          }
          
          clear_field_value();
          
          if(0 == (field_value_ = (char *)safe_malloc_add_2op_(field_value_length, /*+*/1))){
            is_valid_ = false;
          }
          else{
            field_value_length_ = field_value_length;
            std::memcpy(field_value_, field_value, field_value_length);
            field_value_[field_value_length] = '\0';
            compose_field();
          }
          
          return is_valid_;
        }
        bool set_field_value(const char *field_value) // assumes \a field_value is NUL-terminated
        {
          return set_field_value(field_value, strlen(field_value));
        }
        
      protected:
        bool is_valid_;
        ::FLAC__StreamMetadata_VorbisComment_Entry entry_;
        char *field_name_;
        unsigned field_name_length_;
        char *field_value_;
        unsigned field_value_length_;
        
      private:
        void zero()
        {
          is_valid_ = true;
          entry_.length = 0;
          entry_.entry = 0;
          field_name_ = 0;
          field_name_length_ = 0;
          field_value_ = 0;
          field_value_length_ = 0;
        }
        void clear()
        {
          clear_entry();
          clear_field_name();
          clear_field_value();
          is_valid_ = true;
        }
        void clear_entry()
        {
          if(0 != entry_.entry){
            std::free(entry_.entry);
            entry_.entry = 0;
            entry_.length = 0;
          }
        }
        void clear_field_name()
        {
          if(0 != field_name_){
            std::free(field_name_);
            field_name_ = 0;
            field_name_length_ = 0;
          }
        }
        void clear_field_value()
        {
          if(0 != field_value_){
            std::free(field_value_);
            field_value_ = 0;
            field_value_length_ = 0;
          }
        }
        void construct(const char *field, unsigned field_length)
        {
          if(set_field(field, field_length)){
            parse_field();
          }
        }
        void construct(const char *field) // assumes \a field is NUL-terminated
        {
          construct(field, strlen(field));
        }
        void construct(const char *field_name, const char *field_value, unsigned field_value_length)
        {
          if(set_field_name(field_name) && set_field_value(field_value, field_value_length)){
            compose_field();
          }
        }
        void construct(const char *field_name, const char *field_value) // assumes \a field_value is NUL-terminated
        {
          construct(field_name, field_value, strlen(field_value));
        }
        void compose_field()
        {
          clear_entry();
          
          if(0 == (entry_.entry = (FLAC__byte*)safe_malloc_add_4op_(field_name_length_, /*+*/1, /*+*/field_value_length_, /*+*/1))){
            is_valid_ = false;
          }
          else{
            std::memcpy(entry_.entry, field_name_, field_name_length_);
            entry_.length += field_name_length_;
            std::memcpy(entry_.entry + entry_.length, "=", 1);
            entry_.length += 1;
            if(field_value_length_ > 0){
              std::memcpy(entry_.entry + entry_.length, field_value_, field_value_length_);
            }
            entry_.length += field_value_length_;
            entry_.entry[entry_.length] = '\0';
            is_valid_ = true;
          }
        }
        void parse_field()
        {
          clear_field_name();
          clear_field_value();
          
          const char *p = (const char *)memchr(entry_.entry, '=', entry_.length);
          if(0 == p){
            p = (const char *) entry_.entry + entry_.length;
          }
          
          field_name_length_ = (unsigned) (p - (const char *)entry_.entry);
          if(0 == (field_name_ = (char *)safe_malloc_add_2op_(field_name_length_, /*+*/1))){ // +1 for the trailing \0
            is_valid_ = false;
            return;
          }
          std::memcpy(field_name_, entry_.entry, field_name_length_);
          field_name_[field_name_length_] = '\0';

          if(entry_.length - field_name_length_ == 0){
            field_value_length_ = 0;
            if(0 == (field_value_ = (char *)safe_malloc_(0))){
              is_valid_ = false;
              return;
            }
          }
          else{
            field_value_length_ = entry_.length - field_name_length_ - 1;
            if(0 == (field_value_ = (char *)safe_malloc_add_2op_(field_value_length_, /*+*/1))){ // +1 for the trailing \0
              is_valid_ = false;
              return;
            }
            std::memcpy(field_value_, ++p, field_value_length_);
            field_value_[field_value_length_] = '\0';
          }
          
          is_valid_ = true;
        }
        
      }; // [HARK_FLAC::Metadata::VorbisComment::Entry] class Entry is end
      
      //Constructor
      VorbisComment(): Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT), /*copy=*/false){ }
      
      inline VorbisComment(const VorbisComment &object): Prototype(object) { }
      inline VorbisComment(const ::FLAC__StreamMetadata &object): Prototype(object) { }
      inline VorbisComment(const ::FLAC__StreamMetadata *object): Prototype(object) { }
      
      inline VorbisComment(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
      
      //Destructor
      ~VorbisComment(){ }
      
      //Operator
      inline VorbisComment &operator=(const VorbisComment &object) { Prototype::operator=(object); return *this; }
      inline VorbisComment &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
      inline VorbisComment &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
      
      inline VorbisComment &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
      
      inline bool operator==(const VorbisComment &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
      
      inline bool operator!=(const VorbisComment &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
      
      //Getter
      unsigned get_num_comments() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.vorbis_comment.num_comments;
      }
      const FLAC__byte *get_vendor_string() const // NUL-terminated UTF-8 string
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.vorbis_comment.vendor_string.entry;
      }
      Entry get_comment(unsigned index) const
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(index < hark_metadata_object->data.vorbis_comment.num_comments);
        return Entry((const char *)hark_metadata_object->data.vorbis_comment.comments[index].entry, hark_metadata_object->data.vorbis_comment.comments[index].length);
      }
      
      //Setter
      bool set_vendor_string(const FLAC__byte *string) // NUL-terminated UTF-8 string
      {
        HARK_ASSERT(is_valid());
        const ::FLAC__StreamMetadata_VorbisComment_Entry vendor_string = { static_cast<FLAC__uint32>(strlen((const char *)string)), (FLAC__byte*)string }; // we can cheat on const-ness because we make a copy below:
        return (bool) ::FLAC__metadata_object_vorbiscomment_set_vendor_string(hark_metadata_object, vendor_string, /*copy=*/true);
      }
      bool resize_comments(unsigned new_num_comments)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_vorbiscomment_resize_comments(hark_metadata_object, new_num_comments);
      }
      bool set_comment(unsigned index, const Entry &entry)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(index < hark_metadata_object->data.vorbis_comment.num_comments);
        return (bool) ::FLAC__metadata_object_vorbiscomment_set_comment(hark_metadata_object, index, entry.get_entry(), /*copy=*/true);
      }
      bool insert_comment(unsigned index, const Entry &entry)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(index <= hark_metadata_object->data.vorbis_comment.num_comments);
        return (bool) ::FLAC__metadata_object_vorbiscomment_insert_comment(hark_metadata_object, index, entry.get_entry(), /*copy=*/true);
      }
      bool append_comment(const Entry &entry)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_vorbiscomment_append_comment(hark_metadata_object, entry.get_entry(), /*copy=*/true);
      }
      bool replace_comment(const Entry &entry, bool all)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_vorbiscomment_replace_comment(hark_metadata_object, entry.get_entry(), all, /*copy=*/true);
      }
      bool delete_comment(unsigned index)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(index < hark_metadata_object->data.vorbis_comment.num_comments);
        return (bool) ::FLAC__metadata_object_vorbiscomment_delete_comment(hark_metadata_object, index);
      }
      int find_entry_from(unsigned offset, const char *field_name)
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__metadata_object_vorbiscomment_find_entry_from(hark_metadata_object, offset, field_name);
      }
      int remove_entry_matching(const char *field_name)
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__metadata_object_vorbiscomment_remove_entry_matching(hark_metadata_object, field_name);
      }
      int remove_entries_matching(const char *field_name)
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__metadata_object_vorbiscomment_remove_entries_matching(hark_metadata_object, field_name);
      }
      
    }; // [HARK_FLAC::Metadata::VorbisComment] class VorbisComment is end
    class CueSheet: public Prototype {
    public:
      class Track {
      protected:
        ::FLAC__StreamMetadata_CueSheet_Track *hark_metadata_cuesheet_track_object;
        
      public:
        //Constructor
        Track(): hark_metadata_cuesheet_track_object(::FLAC__metadata_object_cuesheet_track_new()){ }
        Track(const ::FLAC__StreamMetadata_CueSheet_Track *track): hark_metadata_cuesheet_track_object(::FLAC__metadata_object_cuesheet_track_clone(track)){ }
        Track(const Track &track): hark_metadata_cuesheet_track_object(::FLAC__metadata_object_cuesheet_track_clone(track.hark_metadata_cuesheet_track_object)){ }
        
        //Operator
        Track &operator=(const Track &track)
        {
          if(0 != hark_metadata_cuesheet_track_object){
            ::FLAC__metadata_object_cuesheet_track_delete(hark_metadata_cuesheet_track_object);
          }
          hark_metadata_cuesheet_track_object = ::FLAC__metadata_object_cuesheet_track_clone(track.hark_metadata_cuesheet_track_object);
          return *this;
        }
        
        //Destructor
        virtual ~Track()
        {
          if(0 != hark_metadata_cuesheet_track_object){
            ::FLAC__metadata_object_cuesheet_track_delete(hark_metadata_cuesheet_track_object);
          }
        }
        
        virtual bool is_valid() const ///< Returns \c true iff object was properly constructed.
        {
          return(0 != hark_metadata_cuesheet_track_object);
        }
        
        //Getter
        inline FLAC__uint64 get_offset() const { return hark_metadata_cuesheet_track_object->offset; }
        inline FLAC__byte get_number() const { return hark_metadata_cuesheet_track_object->number; }
        inline const char *get_isrc() const { return hark_metadata_cuesheet_track_object->isrc; }
        inline unsigned get_type() const { return hark_metadata_cuesheet_track_object->type; }
        inline bool get_pre_emphasis() const { return hark_metadata_cuesheet_track_object->pre_emphasis; }
        
        inline FLAC__byte get_num_indices() const { return hark_metadata_cuesheet_track_object->num_indices; }
        ::FLAC__StreamMetadata_CueSheet_Index get_index(unsigned i) const
        {
          HARK_ASSERT(is_valid());
          HARK_ASSERT(i < hark_metadata_cuesheet_track_object->num_indices);
          return hark_metadata_cuesheet_track_object->indices[i];
        }
        
        inline const ::FLAC__StreamMetadata_CueSheet_Track *get_track() const { return hark_metadata_cuesheet_track_object; }
        
        //Setter
        inline void set_offset(FLAC__uint64 value) { hark_metadata_cuesheet_track_object->offset = value; }
        inline void set_number(FLAC__byte value) { hark_metadata_cuesheet_track_object->number = value; }
        void set_isrc(const char value[12])
        {
          HARK_ASSERT(is_valid());
          HARK_ASSERT(0 != value);
          std::memcpy(hark_metadata_cuesheet_track_object->isrc, value, 12);
          hark_metadata_cuesheet_track_object->isrc[12] = '\0';
        }
        void set_type(unsigned value)
        {
          HARK_ASSERT(is_valid());
          HARK_ASSERT(value <= 1);
          hark_metadata_cuesheet_track_object->type = value;
        }
        inline void set_pre_emphasis(bool value) { hark_metadata_cuesheet_track_object->pre_emphasis = value? 1 : 0; }
        
        void set_index(unsigned i, const ::FLAC__StreamMetadata_CueSheet_Index &index)
        {
          HARK_ASSERT(is_valid());
          HARK_ASSERT(i < hark_metadata_cuesheet_track_object->num_indices);
          hark_metadata_cuesheet_track_object->indices[i] = index;
        }
        
      }; // [HARK_FLAC::Metadata::CueSeet::Track] class Track is end
      
      //Constructor
      CueSheet(): Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET), /*copy=*/false){ }
      
      inline CueSheet(const CueSheet &object): Prototype(object){ }
      inline CueSheet(const ::FLAC__StreamMetadata &object): Prototype(object){ }
      inline CueSheet(const ::FLAC__StreamMetadata *object): Prototype(object){ }
      
      inline CueSheet(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy){ }
      
      //Destructor
      ~CueSheet(){ }
      
      //Operator
      inline CueSheet &operator=(const CueSheet &object) { Prototype::operator=(object); return *this; }
      inline CueSheet &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
      inline CueSheet &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
      
      inline CueSheet &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
      
      inline bool operator==(const CueSheet &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
      
      inline bool operator!=(const CueSheet &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
      
      //Getter
      const char *get_media_catalog_number() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.cue_sheet.media_catalog_number;
      }
      FLAC__uint64 get_lead_in() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.cue_sheet.lead_in;
      }
      bool get_is_cd() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.cue_sheet.is_cd? true : false;
      }
      
      unsigned get_num_tracks() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.cue_sheet.num_tracks;
      }
      Track get_track(unsigned i) const
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(i < hark_metadata_object->data.cue_sheet.num_tracks);
        return Track(hark_metadata_object->data.cue_sheet.tracks + i);
      }
      
      //Setter
      void set_media_catalog_number(const char value[128])
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(0 != value);
        std::memcpy(hark_metadata_object->data.cue_sheet.media_catalog_number, value, 128);
        hark_metadata_object->data.cue_sheet.media_catalog_number[128] = '\0';
      }
      void set_lead_in(FLAC__uint64 value)
      {
        HARK_ASSERT(is_valid());
        hark_metadata_object->data.cue_sheet.lead_in = value;
      }
      void set_is_cd(bool value)
      {
        HARK_ASSERT(is_valid());
        hark_metadata_object->data.cue_sheet.is_cd = value;
      }
      
      void set_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(track_num < hark_metadata_object->data.cue_sheet.num_tracks);
        HARK_ASSERT(index_num < hark_metadata_object->data.cue_sheet.tracks[track_num].num_indices);
        hark_metadata_object->data.cue_sheet.tracks[track_num].indices[index_num] = index;
      }
      bool resize_indices(unsigned track_num, unsigned new_num_indices)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(track_num < hark_metadata_object->data.cue_sheet.num_tracks);
        return (bool) ::FLAC__metadata_object_cuesheet_track_resize_indices(hark_metadata_object, track_num, new_num_indices);
      }
      bool insert_index(unsigned track_num, unsigned index_num, const ::FLAC__StreamMetadata_CueSheet_Index &index)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(track_num < hark_metadata_object->data.cue_sheet.num_tracks);
        HARK_ASSERT(index_num <= hark_metadata_object->data.cue_sheet.tracks[track_num].num_indices);
        return (bool) ::FLAC__metadata_object_cuesheet_track_insert_index(hark_metadata_object, track_num, index_num, index);
      }
      bool insert_blank_index(unsigned track_num, unsigned index_num)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(track_num < hark_metadata_object->data.cue_sheet.num_tracks);
        HARK_ASSERT(index_num <= hark_metadata_object->data.cue_sheet.tracks[track_num].num_indices);
        return (bool) ::FLAC__metadata_object_cuesheet_track_insert_blank_index(hark_metadata_object, track_num, index_num);
      }
      bool delete_index(unsigned track_num, unsigned index_num)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(track_num < hark_metadata_object->data.cue_sheet.num_tracks);
        HARK_ASSERT(index_num < hark_metadata_object->data.cue_sheet.tracks[track_num].num_indices);
        return (bool) ::FLAC__metadata_object_cuesheet_track_delete_index(hark_metadata_object, track_num, index_num);
      }
      bool resize_tracks(unsigned new_num_tracks)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_cuesheet_resize_tracks(hark_metadata_object, new_num_tracks);
      }
      bool set_track(unsigned i, const Track &track)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(i < hark_metadata_object->data.cue_sheet.num_tracks);
        // We can safely const_cast since copy=true
        return (bool) ::FLAC__metadata_object_cuesheet_set_track(hark_metadata_object, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
      }
      bool insert_track(unsigned i, const Track &track)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(i <= hark_metadata_object->data.cue_sheet.num_tracks);
        // We can safely const_cast since copy=true
        return (bool) ::FLAC__metadata_object_cuesheet_insert_track(hark_metadata_object, i, const_cast< ::FLAC__StreamMetadata_CueSheet_Track*>(track.get_track()), /*copy=*/true);
      }
      bool insert_blank_track(unsigned i)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(i <= hark_metadata_object->data.cue_sheet.num_tracks);
        return (bool) ::FLAC__metadata_object_cuesheet_insert_blank_track(hark_metadata_object, i);
      }
      bool delete_track(unsigned i)
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(i < hark_metadata_object->data.cue_sheet.num_tracks);
        return (bool) ::FLAC__metadata_object_cuesheet_delete_track(hark_metadata_object, i);
      }
      bool is_legal(bool check_cd_da_subset = false, const char **violation = 0) const
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_cuesheet_is_legal(hark_metadata_object, check_cd_da_subset, violation);
      }
      FLAC__uint32 calculate_cddb_id() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__metadata_object_cuesheet_calculate_cddb_id(hark_metadata_object);
      }
      
    }; // [HARK_FLAC::Metadata::CueSeet] class CueSeet is end
    class Picture: public Prototype {
    public:
      //Constructor
      Picture(): Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE), /*copy=*/false){ }
      
      inline Picture(const Picture &object): Prototype(object) { }
      inline Picture(const ::FLAC__StreamMetadata &object): Prototype(object) { }
      inline Picture(const ::FLAC__StreamMetadata *object): Prototype(object) { }
      
      inline Picture(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
      
      //Destructor
      ~Picture(){ }
      
      //Operator
      inline Picture &operator=(const Picture &object) { Prototype::operator=(object); return *this; }
      inline Picture &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
      inline Picture &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
      
      inline Picture &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
      
      inline bool operator==(const Picture &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
      
      inline bool operator!=(const Picture &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
      
      //Getter
      ::FLAC__StreamMetadata_Picture_Type get_type() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.picture.type;
      }
      const char *get_mime_type() const // NUL-terminated printable ASCII string
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.picture.mime_type;
      }
      const FLAC__byte *get_description() const // NUL-terminated UTF-8 string
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.picture.description;
      }
      FLAC__uint32 get_width() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.picture.width;
      }
      FLAC__uint32 get_height() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.picture.height;
      }
      FLAC__uint32 get_depth() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.picture.depth;
      }
      FLAC__uint32 get_colors() const ///< a return value of \c 0 means true-color, i.e. 2^depth colors
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.picture.colors;
      }
      FLAC__uint32 get_data_length() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.picture.data_length;
      }
      const FLAC__byte *get_data() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.picture.data;
      }
      
      //Setter
      void set_type(::FLAC__StreamMetadata_Picture_Type type)
      {
        HARK_ASSERT(is_valid());
        hark_metadata_object->data.picture.type = type;
      }
      bool set_mime_type(const char *string) // NUL-terminated printable ASCII string
      {
        HARK_ASSERT(is_valid());
        // We can safely const_cast since copy=true
        return (bool) ::FLAC__metadata_object_picture_set_mime_type(hark_metadata_object, const_cast<char*>(string), /*copy=*/true);
      }
      bool set_description(const FLAC__byte *string) // NUL-terminated UTF-8 string
      {
        HARK_ASSERT(is_valid());
        // We can safely const_cast since copy=true
        return (bool) ::FLAC__metadata_object_picture_set_description(hark_metadata_object, const_cast<FLAC__byte*>(string), /*copy=*/true);
      }
      void set_width(FLAC__uint32 value) const
      {
        HARK_ASSERT(is_valid());
        hark_metadata_object->data.picture.width = value;
      }
      void set_height(FLAC__uint32 value) const
      {
        HARK_ASSERT(is_valid());
        hark_metadata_object->data.picture.height = value;
      }
      void set_depth(FLAC__uint32 value) const
      {
        HARK_ASSERT(is_valid());
        hark_metadata_object->data.picture.depth = value;
      }
      void set_colors(FLAC__uint32 value) const ///< a value of \c 0 means true-color, i.e. 2^depth colors
      {
        HARK_ASSERT(is_valid());
        hark_metadata_object->data.picture.colors = value;
      }
      bool set_data(const FLAC__byte *data, FLAC__uint32 data_length)
      {
        HARK_ASSERT(is_valid());
        // We can safely const_cast since copy=true
        return (bool) ::FLAC__metadata_object_picture_set_data(hark_metadata_object, const_cast<FLAC__byte*>(data), data_length, /*copy=*/true);
      }
      bool is_legal(const char **violation)
      {
        HARK_ASSERT(is_valid());
        return (bool)::FLAC__metadata_object_picture_is_legal(hark_metadata_object, violation);
      }
      
    }; // [HARK_FLAC::Metadata::Picture] class Picture is end
    class Unknown: public Prototype {
    public:
      //Constructor
      Unknown(): Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION), /*copy=*/false){ }
      
      inline Unknown(const Unknown &object): Prototype(object) { }
      inline Unknown(const ::FLAC__StreamMetadata &object): Prototype(object) { }
      inline Unknown(const ::FLAC__StreamMetadata *object): Prototype(object) { }
      
      inline Unknown(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
      
      //Destructor
      ~Unknown(){ }
      
      //Operator
      inline Unknown &operator=(const Unknown &object) { Prototype::operator=(object); return *this; }
      inline Unknown &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
      inline Unknown &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
      
      inline Unknown &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
      
      inline bool operator==(const Unknown &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
      inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
      
      inline bool operator!=(const Unknown &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
      inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
      
      //Getter
      const FLAC__byte *get_data() const
      {
        HARK_ASSERT(is_valid());
        return hark_metadata_object->data.application.data;
      }
      
      //Setter
      bool set_data(const FLAC__byte *data, unsigned length)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_application_set_data(hark_metadata_object, (FLAC__byte*)data, length, true);
      }
      bool set_data(FLAC__byte *data, unsigned length, bool copy)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_object_application_set_data(hark_metadata_object, data, length, copy);
      }
      
    }; // [HARK_FLAC::Metadata::Unknown] class Unknown is end
    Prototype *clone(const Prototype *object)
    {
      HARK_ASSERT(0 != object);

      const StreamInfo *streaminfo = dynamic_cast<const StreamInfo *>(object);
      const Padding *padding = dynamic_cast<const Padding *>(object);
      const Application *application = dynamic_cast<const Application *>(object);
      const SeekTable *seektable = dynamic_cast<const SeekTable *>(object);
      const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
      const CueSheet *cuesheet = dynamic_cast<const CueSheet *>(object);
      const Picture *picture = dynamic_cast<const Picture *>(object);
      const Unknown *unknown = dynamic_cast<const Unknown *>(object);

      if(0 != streaminfo){         return new StreamInfo(*streaminfo); }
      else if(0 != padding){       return new Padding(*padding); }
      else if(0 != application){   return new Application(*application); }
      else if(0 != seektable){     return new SeekTable(*seektable); }
      else if(0 != vorbiscomment){ return new VorbisComment(*vorbiscomment); }
      else if(0 != cuesheet){      return new CueSheet(*cuesheet); }
      else if(0 != picture){       return new Picture(*picture); }
      else if(0 != unknown){       return new Unknown(*unknown); }
      else{   HARK_ASSERT(0);      return 0; }
    }
    
    namespace local {
      Prototype *construct_block(::FLAC__StreamMetadata *object)
      {
        Prototype *ret = 0;
        switch(object->type) {
        case FLAC__METADATA_TYPE_STREAMINFO:     ret = new StreamInfo(object, /*copy=*/false);    break;
        case FLAC__METADATA_TYPE_PADDING:        ret = new Padding(object, /*copy=*/false);       break;
        case FLAC__METADATA_TYPE_APPLICATION:    ret = new Application(object, /*copy=*/false);   break;
        case FLAC__METADATA_TYPE_SEEKTABLE:      ret = new SeekTable(object, /*copy=*/false);     break;
        case FLAC__METADATA_TYPE_VORBIS_COMMENT: ret = new VorbisComment(object, /*copy=*/false); break;
        case FLAC__METADATA_TYPE_CUESHEET:       ret = new CueSheet(object, /*copy=*/false);      break;
        case FLAC__METADATA_TYPE_PICTURE:        ret = new Picture(object, /*copy=*/false);       break;
        default:                                 ret = new Unknown(object, /*copy=*/false);       break;
        }
        return ret;
      }
    } // [HARK_FLAC::Metadata::local] namespace local is end
    
    ////Metadata Level 0 interface
    bool get_streaminfo(const char *filename, StreamInfo &streaminfo) ///< See FLAC__metadata_get_streaminfo().
    {
      HARK_ASSERT(0 != filename);
      ::FLAC__StreamMetadata object;
      if(::FLAC__metadata_get_streaminfo(filename, &object)){
        streaminfo = object;
        return true;
      }
      else{
        return false;
      }
    }
    
    bool get_tags(const char *filename, VorbisComment *&tags) ///< See FLAC__metadata_get_tags().
    {
      HARK_ASSERT(0 != filename);
      ::FLAC__StreamMetadata *object;
      tags = 0;
      if(::FLAC__metadata_get_tags(filename, &object)){
        tags = new VorbisComment(object, /*copy=*/false);
        return true;
      }
      else{
        return false;
      }
    }
    bool get_tags(const char *filename, VorbisComment &tags) ///< See FLAC__metadata_get_tags().
    {
      HARK_ASSERT(0 != filename);
      ::FLAC__StreamMetadata *object;
      if(::FLAC__metadata_get_tags(filename, &object)){
        tags.assign(object, /*copy=*/false);
        return true;
      }
      else{
        return false;
      }
    }
    
    bool get_cuesheet(const char *filename, CueSheet *&cuesheet) ///< See FLAC__metadata_get_cuesheet().
    {
      HARK_ASSERT(0 != filename);
      ::FLAC__StreamMetadata *object;
      cuesheet = 0;
      if(::FLAC__metadata_get_cuesheet(filename, &object)){
        cuesheet = new CueSheet(object, /*copy=*/false);
        return true;
      }
      else{
        return false;
      }
    }
    bool get_cuesheet(const char *filename, CueSheet &cuesheet) ///< See FLAC__metadata_get_cuesheet().
    {
      HARK_ASSERT(0 != filename);
      ::FLAC__StreamMetadata *object;
      if(::FLAC__metadata_get_cuesheet(filename, &object)){
        cuesheet.assign(object, /*copy=*/false);
        return true;
      }
      else{
        return false;
      }
    }
    
    bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors) ///< See FLAC__metadata_get_picture().
    {
      HARK_ASSERT(0 != filename);
      ::FLAC__StreamMetadata *object;
      picture = 0;
      if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)){
        picture = new Picture(object, /*copy=*/false);
        return true;
      }
      else{
        return false;
      }
    }
    bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors) ///< See FLAC__metadata_get_picture().
    {
      HARK_ASSERT(0 != filename);
      ::FLAC__StreamMetadata *object;
      if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth, max_colors)){
        picture.assign(object, /*copy=*/false);
        return true;
      }
      else{
        return false;
      }
    }
    
    ////Metadata Level 1 interface
    class SimpleIterator {
    public:
      class Status {
      protected:
        ::FLAC__Metadata_SimpleIteratorStatus status_;
      public:
        inline Status(::FLAC__Metadata_SimpleIteratorStatus status): status_(status) { }
        inline operator ::FLAC__Metadata_SimpleIteratorStatus() const { return status_; }
        inline const char *as_cstring() const { return ::FLAC__Metadata_SimpleIteratorStatusString[status_]; }
      };
      
      SimpleIterator(): iterator_(::FLAC__metadata_simple_iterator_new()){ }
      ~SimpleIterator(){ clear(); }
      
      bool is_valid() const ///< Returns \c true iff object was properly constructed.
      {
        return 0 != iterator_;
      }
      
      bool init(const char *filename, bool read_only, bool preserve_file_stats) ///< See FLAC__metadata_simple_iterator_init().
      {
        HARK_ASSERT(0 != filename);
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_simple_iterator_init(iterator_, filename, read_only, preserve_file_stats);
      }
      
      Status status()                                                    ///< See FLAC__metadata_simple_iterator_status().
      {
        HARK_ASSERT(is_valid());
        return Status(::FLAC__metadata_simple_iterator_status(iterator_));
      }
      bool is_writable() const                                           ///< See FLAC__metadata_simple_iterator_is_writable().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_simple_iterator_is_writable(iterator_);
      }
      
      bool next()                                                        ///< See FLAC__metadata_simple_iterator_next().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_simple_iterator_next(iterator_);
      }
      bool prev()                                                        ///< See FLAC__metadata_simple_iterator_prev().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_simple_iterator_prev(iterator_);
      }
      bool is_last() const                                               ///< See FLAC__metadata_simple_iterator_is_last().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_simple_iterator_is_last(iterator_);
      }
      
      off_t get_block_offset() const                                     ///< See FLAC__metadata_simple_iterator_get_block_offset().
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__metadata_simple_iterator_get_block_offset(iterator_);
      }
      ::FLAC__MetadataType get_block_type() const                        ///< See FLAC__metadata_simple_iterator_get_block_type().
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__metadata_simple_iterator_get_block_type(iterator_);
      }
      unsigned get_block_length() const                                  ///< See FLAC__metadata_simple_iterator_get_block_length().
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__metadata_simple_iterator_get_block_length(iterator_);
      }
      bool get_application_id(FLAC__byte *id)                            ///< See FLAC__metadata_simple_iterator_get_application_id().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_simple_iterator_get_application_id(iterator_, id);
      }
      Prototype *get_block()                                             ///< See FLAC__metadata_simple_iterator_get_block().
      {
        HARK_ASSERT(is_valid());
        return local::construct_block(::FLAC__metadata_simple_iterator_get_block(iterator_));
      }
      bool set_block(Prototype *block, bool use_padding = true)          ///< See FLAC__metadata_simple_iterator_set_block().
      {
        HARK_ASSERT(0 != block);
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_simple_iterator_set_block(iterator_, block->hark_metadata_object, use_padding);
      }
      bool insert_block_after(Prototype *block, bool use_padding = true) ///< See FLAC__metadata_simple_iterator_insert_block_after().
      {
        HARK_ASSERT(0 != block);
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_simple_iterator_insert_block_after(iterator_, block->hark_metadata_object, use_padding);
      }
      bool delete_block(bool use_padding = true)                         ///< See FLAC__metadata_simple_iterator_delete_block().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_simple_iterator_delete_block(iterator_, use_padding);
      }
      
    protected:
      ::FLAC__Metadata_SimpleIterator *iterator_;
      void clear()
      {
        if(0 != iterator_){
          FLAC__metadata_simple_iterator_delete(iterator_);
        }
        iterator_ = 0;
      }
      
    }; // [HARK_FLAC::Metadata::SimpleIterator] class SimpleIterator is end
    
    ////Metadata Level 2 interface
    class Chain {
    public:
      class Status {
      protected:
        ::FLAC__Metadata_ChainStatus status_;
        
      public:
        //Constructor
        inline Status(::FLAC__Metadata_ChainStatus status): status_(status) { }
        
        //Operator
        inline operator ::FLAC__Metadata_ChainStatus() const { return status_; }
        
        inline const char *as_cstring() const { return ::FLAC__Metadata_ChainStatusString[status_]; }
        
      }; // [HARK_FLAC::Metadata::Chain::Status] class Status is end
      
      //Constructor
      Chain(): chain_(::FLAC__metadata_chain_new()){ }
      
      //Destructor
      ~Chain(){ clear(); }
      
      friend class Iterator;
      
      bool is_valid() const{ return 0 != chain_; } ///< Returns \c true iff object was properly constructed.
      
      Status status()                                                ///< See FLAC__metadata_chain_status().
      {
        HARK_ASSERT(is_valid());
        return Status(::FLAC__metadata_chain_status(chain_));
      }
      
      bool read(const char *filename, bool is_ogg = false)                                ///< See FLAC__metadata_chain_read(), FLAC__metadata_chain_read_ogg().
      {
        HARK_ASSERT(0 != filename);
        HARK_ASSERT(is_valid());
        return (is_ogg ? (bool) ::FLAC__metadata_chain_read_ogg(chain_, filename)
                       : (bool) ::FLAC__metadata_chain_read(chain_, filename));
      }
      bool read(FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, bool is_ogg = false)  ///< See FLAC__metadata_chain_read_with_callbacks(), FLAC__metadata_chain_read_ogg_with_callbacks().
      {
        HARK_ASSERT(is_valid());
        return (is_ogg ? (bool) ::FLAC__metadata_chain_read_ogg_with_callbacks(chain_, handle, callbacks)
                       : (bool) ::FLAC__metadata_chain_read_with_callbacks(chain_, handle, callbacks));
      }
      
      bool check_if_tempfile_needed(bool use_padding)                ///< See FLAC__metadata_chain_check_if_tempfile_needed().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_chain_check_if_tempfile_needed(chain_, use_padding);
      }
      
      bool write(bool use_padding = true, bool preserve_file_stats = false) ///< See FLAC__metadata_chain_write().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_chain_write(chain_, use_padding, preserve_file_stats);
      }
      bool write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks) ///< See FLAC__metadata_chain_write_with_callbacks().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_chain_write_with_callbacks(chain_, use_padding, handle, callbacks);
      }
      bool write(bool use_padding, ::FLAC__IOHandle handle, ::FLAC__IOCallbacks callbacks, ::FLAC__IOHandle temp_handle, ::FLAC__IOCallbacks temp_callbacks) ///< See FLAC__metadata_chain_write_with_callbacks_and_tempfile().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain_, use_padding, handle, callbacks, temp_handle, temp_callbacks);
      }
      
      void merge_padding()                                           ///< See FLAC__metadata_chain_merge_padding().
      {
        HARK_ASSERT(is_valid());
        ::FLAC__metadata_chain_merge_padding(chain_);
      }
      void sort_padding()                                            ///< See FLAC__metadata_chain_sort_padding().
      {
        HARK_ASSERT(is_valid());
        ::FLAC__metadata_chain_sort_padding(chain_);
      }
      
    protected:
      ::FLAC__Metadata_Chain *chain_;
      void clear()
      {
        if(0 != chain_){
          FLAC__metadata_chain_delete(chain_);
        }
        chain_ = 0;
      }
      
    }; // [HARK_FLAC::Metadata::Chain] class Chain is end
    class Iterator {
    public:
      //Constructor
      Iterator(): iterator_(::FLAC__metadata_iterator_new()){ }
      
      //Destructor
      ~Iterator(){ clear(); }
      
      bool is_valid() const{ return 0 != iterator_; } ///< Returns \c true iff object was properly constructed.
      
      void init(Chain &chain)                       ///< See FLAC__metadata_iterator_init().
      {
        HARK_ASSERT(is_valid());
        HARK_ASSERT(chain.is_valid());
        ::FLAC__metadata_iterator_init(iterator_, chain.chain_);
      }
      
      bool next()                                   ///< See FLAC__metadata_iterator_next().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_iterator_next(iterator_);
      }
      bool prev()                                   ///< See FLAC__metadata_iterator_prev().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_iterator_prev(iterator_);
      }
      
      ::FLAC__MetadataType get_block_type() const   ///< See FLAC__metadata_iterator_get_block_type().
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__metadata_iterator_get_block_type(iterator_);
      }
      Prototype *get_block()                        ///< See FLAC__metadata_iterator_get_block().
      {
        HARK_ASSERT(is_valid());
        Prototype *block = local::construct_block(::FLAC__metadata_iterator_get_block(iterator_));
        if(0 != block){
          block->set_reference(true);
        }
        return block;
      }
      bool set_block(Prototype *block)              ///< See FLAC__metadata_iterator_set_block().
      {
        HARK_ASSERT(0 != block);
        HARK_ASSERT(is_valid());
        bool ret = (bool) ::FLAC__metadata_iterator_set_block(iterator_, block->hark_metadata_object);
        if(ret){
          block->set_reference(true);
          delete block;
        }
        return ret;
      }
      bool delete_block(bool replace_with_padding)  ///< See FLAC__metadata_iterator_delete_block().
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__metadata_iterator_delete_block(iterator_, replace_with_padding);
      }
      bool insert_block_before(Prototype *block)    ///< See FLAC__metadata_iterator_insert_block_before().
      {
        HARK_ASSERT(0 != block);
        HARK_ASSERT(is_valid());
        bool ret = (bool)::FLAC__metadata_iterator_insert_block_before(iterator_, block->hark_metadata_object);
        if(ret){
          block->set_reference(true);
          delete block;
        }
        return ret;
      }
      bool insert_block_after(Prototype *block)     ///< See FLAC__metadata_iterator_insert_block_after().
      {
        HARK_ASSERT(0 != block);
        HARK_ASSERT(is_valid());
        bool ret = (bool)::FLAC__metadata_iterator_insert_block_after(iterator_, block->hark_metadata_object);
        if(ret){
          block->set_reference(true);
          delete block;
        }
        return ret;
      }
      
    protected:
      ::FLAC__Metadata_Iterator *iterator_;
      void clear()
      {
        if(0 != iterator_){
          FLAC__metadata_iterator_delete(iterator_);
        }
        iterator_ = 0;
      }
      
    }; // [HARK_FLAC::Metadata::Iterator] class Iterator is end
    
  } // [HARK_FLAC::Metadata] namespace Metadata is end
  namespace Decoder {
    class Stream {
    public:
      class State {
      public:
        inline State(::FLAC__StreamDecoderState state): state_(state) { }
        inline operator ::FLAC__StreamDecoderState() const { return state_; }
        inline const char *as_cstring() const { return ::FLAC__StreamDecoderStateString[state_]; }
        inline const char *resolved_as_cstring(const Stream &decoder) const { return ::FLAC__stream_decoder_get_resolved_state_string(decoder.hark_flac_decoder); }
      protected:
        ::FLAC__StreamDecoderState state_;
      }; // [HARK_FLAC::Decoder::Stream::State] class State is end
      
      //Constructor
      Stream(): hark_flac_decoder(::FLAC__stream_decoder_new()) {};
      
      //Destructor
      virtual ~Stream()
      {
        if(0 != hark_flac_decoder){
          (void) ::FLAC__stream_decoder_finish(hark_flac_decoder);
          ::FLAC__stream_decoder_delete(hark_flac_decoder);
        }
      }
      bool is_valid() const
      {
        return 0 != hark_flac_decoder;
      }
      inline operator bool() const { return is_valid(); }
      bool set_ogg_serial_number(long value)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_set_ogg_serial_number(hark_flac_decoder, value);
      }
      
      bool set_md5_checking(bool value)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_set_md5_checking(hark_flac_decoder, value);
      }
      bool set_metadata_respond(::FLAC__MetadataType type)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_set_metadata_respond(hark_flac_decoder, type);
      }
      bool set_metadata_respond_application(const FLAC__byte id[4])
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_set_metadata_respond_application(hark_flac_decoder, id);
      }
      bool set_metadata_respond_all()
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_set_metadata_respond_all(hark_flac_decoder);
      }
      bool set_metadata_ignore(::FLAC__MetadataType type)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_set_metadata_ignore(hark_flac_decoder, type);
      }
      bool set_metadata_ignore_application(const FLAC__byte id[4])
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_set_metadata_ignore_application(hark_flac_decoder, id);
      }
      bool set_metadata_ignore_all()
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_set_metadata_ignore_all(hark_flac_decoder);
      }
      State get_state() const
      {
        HARK_ASSERT(is_valid());
        return State(::FLAC__stream_decoder_get_state(hark_flac_decoder));
      }
      bool get_md5_checking() const
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_get_md5_checking(hark_flac_decoder);
      }
      FLAC__uint64 get_total_samples() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_decoder_get_total_samples(hark_flac_decoder);
      }
      unsigned get_channels() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_decoder_get_channels(hark_flac_decoder);
      }
      ::FLAC__ChannelAssignment get_channel_assignment() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_decoder_get_channel_assignment(hark_flac_decoder);
      }
      unsigned get_bits_per_sample() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_decoder_get_bits_per_sample(hark_flac_decoder);
      }
      unsigned get_sample_rate() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_decoder_get_sample_rate(hark_flac_decoder);
      }
      unsigned get_blocksize() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_decoder_get_blocksize(hark_flac_decoder);
      }
      bool get_decode_position(FLAC__uint64 *position) const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_decoder_get_decode_position(hark_flac_decoder, position);
      }
      
      ::FLAC__StreamDecoderInitStatus init()
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_decoder_init_stream(hark_flac_decoder, read_callback_, seek_callback_, tell_callback_, length_callback_, eof_callback_, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
      }
      ::FLAC__StreamDecoderInitStatus init_ogg()
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_decoder_init_ogg_stream(hark_flac_decoder, read_callback_, seek_callback_, tell_callback_, length_callback_, eof_callback_, write_callback_, metadata_callback_, error_callback_, /*client_data=*/(void*)this);
      }
      
      bool finish()
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_finish(hark_flac_decoder);
      }
      
      bool flush()
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_flush(hark_flac_decoder);
      }
      bool reset()
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_reset(hark_flac_decoder);
      }
      
      bool process_single()
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_process_single(hark_flac_decoder);
      }
      bool process_until_end_of_metadata()
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_process_until_end_of_metadata(hark_flac_decoder);
      }
      bool process_until_end_of_stream()
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_process_until_end_of_stream(hark_flac_decoder);
      }
      bool skip_single_frame()
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_skip_single_frame(hark_flac_decoder);
      }
      
      bool seek_absolute(FLAC__uint64 sample)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_decoder_seek_absolute(hark_flac_decoder, sample);
      }
      
    protected:
      virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) = 0;
      virtual ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset)
      {
        (void) absolute_byte_offset;
        return ::FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
      }
      virtual ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset)
      {
        (void) absolute_byte_offset;
        return ::FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
      }
      virtual ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length)
      {
        (void) stream_length;
        return ::FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
      }
      virtual bool eof_callback()
      {
        return false;
      }
      virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) = 0;
      virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata)
      {
        (void) metadata;
      }
      virtual void error_callback(::FLAC__StreamDecoderErrorStatus status) = 0;
#if (defined _MSC_VER) || (defined __BORLANDC__) || (defined __GNUG__ && (__GNUG__ < 2 || (__GNUG__ == 2 && __GNUC_MINOR__ < 96))) || (defined __SUNPRO_CC)
      // lame hack: some MSVC/GCC versions can't see a protected decoder_ from nested State::resolved_as_cstring()
      friend State;
#endif
      ::FLAC__StreamDecoder *hark_flac_decoder;
      
      static ::FLAC__StreamDecoderReadStatus read_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
      {
        (void) decoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->read_callback(buffer, bytes);
      }
      static ::FLAC__StreamDecoderSeekStatus seek_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
      {
        (void) decoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->seek_callback(absolute_byte_offset);
      }
      static ::FLAC__StreamDecoderTellStatus tell_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
      {
        (void) decoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->tell_callback(absolute_byte_offset);
      }
      static ::FLAC__StreamDecoderLengthStatus length_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
      {
        (void) decoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->length_callback(stream_length);
      }
      static FLAC__bool eof_callback_(const ::FLAC__StreamDecoder *decoder, void *client_data)
      {
        (void) decoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->eof_callback();
      }
      static ::FLAC__StreamDecoderWriteStatus write_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
      {
        (void) decoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->write_callback(frame, buffer);
      }
      static void metadata_callback_(const ::FLAC__StreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *client_data)
      {
        (void) decoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        instance->metadata_callback(metadata);
      }
      static void error_callback_(const ::FLAC__StreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *client_data)
      {
        (void) decoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        instance->error_callback(status);
      }
      
    private:
      Stream(const Stream &);
      void operator=(const Stream &);
      
    }; // [HARK_FLAC::Decoder::Stream] class Stream is end
    class File: public Stream {
    public:
      //Constructor
      File(): Stream(){ }
      
      //Destructor
      ~File(){ }
      
      ::FLAC__StreamDecoderInitStatus init(FILE *file)
      {
        HARK_ASSERT(0 != hark_flac_decoder);
        return ::FLAC__stream_decoder_init_FILE(hark_flac_decoder, file, Stream::write_callback_, Stream::metadata_callback_, Stream::error_callback_, /*client_data=*/(void*)this);
      }
      ::FLAC__StreamDecoderInitStatus init(const char *filename)
      {
        HARK_ASSERT(0 != hark_flac_decoder);
        return ::FLAC__stream_decoder_init_file(hark_flac_decoder, filename, Stream::write_callback_, Stream::metadata_callback_, Stream::error_callback_, /*client_data=*/(void*)this);
      }
      ::FLAC__StreamDecoderInitStatus init(const std::string &filename)
      {
        return init(filename.c_str());
      }
      ::FLAC__StreamDecoderInitStatus init_ogg(FILE *file)
      {
        HARK_ASSERT(0 != hark_flac_decoder);
        return ::FLAC__stream_decoder_init_ogg_FILE(hark_flac_decoder, file, Stream::write_callback_, Stream::metadata_callback_, Stream::error_callback_, /*client_data=*/(void*)this);
      }
      ::FLAC__StreamDecoderInitStatus init_ogg(const char *filename)
      {
        HARK_ASSERT(0 != hark_flac_decoder);
        return ::FLAC__stream_decoder_init_ogg_file(hark_flac_decoder, filename, Stream::write_callback_, Stream::metadata_callback_, Stream::error_callback_, /*client_data=*/(void*)this);
      }
      ::FLAC__StreamDecoderInitStatus init_ogg(const std::string &filename)
      {
        return init_ogg(filename.c_str());
      }
      
    protected:
      virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes)
      {
        (void)buffer, (void)bytes;
        HARK_ASSERT(false);
        return ::FLAC__STREAM_DECODER_READ_STATUS_ABORT;
      }
      
    private:
      File(const File &);
      void operator=(const File &);
      
    }; // [HARK_FLAC::Decoder::File] class File is end
  } // [HARK_FLAC::Decoder] namespace Decoder is end
  namespace Encoder {
    class Stream {
    public:
      class State {
      public:
        inline State(::FLAC__StreamEncoderState state): state_(state) { }
        inline operator ::FLAC__StreamEncoderState() const { return state_; }
        inline const char *as_cstring() const { return ::FLAC__StreamEncoderStateString[state_]; }
        inline const char *resolved_as_cstring(const Stream &encoder) const { return ::FLAC__stream_encoder_get_resolved_state_string(encoder.hark_flac_encoder); }
      protected:
        ::FLAC__StreamEncoderState state_;
      }; // [HARK_FLAC::Decoder::Stream::State] class State is end
      Stream(): hark_flac_encoder(::FLAC__stream_encoder_new()) { }
      virtual ~Stream()
      {
        if(0 != hark_flac_encoder){
          (void) ::FLAC__stream_encoder_finish(hark_flac_encoder);
          ::FLAC__stream_encoder_delete(hark_flac_encoder);
        }
      }
      bool is_valid() const
      {
        return (0 != hark_flac_encoder);
      }
      inline operator bool() const { return is_valid(); }
      
      //// Setter
      bool set_ogg_serial_nmber(long serial_number)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_ogg_serial_number(hark_flac_encoder, serial_number);
      }
      bool set_verify(bool verify_flag)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_verify(hark_flac_encoder, verify_flag);
      }
      bool set_streamable_subset(bool subset_flag)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_streamable_subset(hark_flac_encoder, subset_flag);
      }
      bool set_channels(unsigned channels)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_channels(hark_flac_encoder, channels);
      }
      bool set_bits_per_sample(unsigned bits)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_bits_per_sample(hark_flac_encoder, bits);
      }
      bool set_sample_rate(unsigned rate)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_sample_rate(hark_flac_encoder, rate);
      }
      bool set_compression_level(unsigned level)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_compression_level(hark_flac_encoder, level);
      }
      bool set_blocksize(unsigned blocksize)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_blocksize(hark_flac_encoder, blocksize);
      }
      bool set_do_mid_side_stereo(bool do_mid_side_stereo)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_do_mid_side_stereo(hark_flac_encoder, do_mid_side_stereo);
      }
      bool set_loose_mid_side_stereo(bool loose_mid_side_stereo)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_loose_mid_side_stereo(hark_flac_encoder, loose_mid_side_stereo);
      }
      bool set_apodization(const char *specification)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_apodization(hark_flac_encoder, specification);
      }
      bool set_max_lpc_order(unsigned max_lpc_order)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_max_lpc_order(hark_flac_encoder, max_lpc_order);
      }
      bool set_qlp_coeff_precision(unsigned qlp_coeff_precision)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_qlp_coeff_precision(hark_flac_encoder, qlp_coeff_precision);
      }
      bool set_do_qlp_coeff_prec_search(bool do_qlp_coeff_prec_search)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_do_qlp_coeff_prec_search(hark_flac_encoder, do_qlp_coeff_prec_search);
      }
      bool set_do_escape_coding(bool do_escape_coding)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_do_escape_coding(hark_flac_encoder, do_escape_coding);
      }
      bool set_do_exhaustive_model_search(bool do_exhaustive_model_search)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_do_exhaustive_model_search(hark_flac_encoder, do_exhaustive_model_search);
      }
      bool set_min_residual_partition_order(unsigned min_residual_partition_order)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_min_residual_partition_order(hark_flac_encoder, min_residual_partition_order);
      }
      bool set_max_residual_partition_order(unsigned max_residual_partition_order)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_max_residual_partition_order(hark_flac_encoder, max_residual_partition_order);
      }
      bool set_rice_parameter_search_dist(unsigned rice_parameter_search_dist)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_rice_parameter_search_dist(hark_flac_encoder, rice_parameter_search_dist);
      }
      bool set_total_samples_estimate(FLAC__uint64 total_samples_estimate)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_total_samples_estimate(hark_flac_encoder, total_samples_estimate);
      }
      bool set_metadata(::FLAC__StreamMetadata **metadata, unsigned num_blocks)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_set_metadata(hark_flac_encoder, metadata, num_blocks);
      }
      bool set_metadata(Metadata::Prototype **metadata, unsigned num_blocks)
      {
        HARK_ASSERT(is_valid());
////#if (defined _MSC_VER) || (defined __BORLANDC__) || (defined __SUNPRO_CC)
////        // MSVC++ can't handle: "::FLAC__StreamMetadata *m[num_blocks];" // so we do this ugly workaround
////        ::FLAC__StreamMetadata **m = new ::FLAC__StreamMetadata*[num_blocks];
////        for(unsigned i=0; i<num_blocks; i++){
////          m[i] = const_cast< ::FLAC__StreamMetadata* >((const ::FLAC__StreamMetadata*) metadata[i]);
////        }
////        // complete the hack
////        const bool ok = (bool)::FLAC__stream_encoder_set_metadata(encoder_, m, num_blocks);
////        delete [] m;
////        return ok;
////#else
        ::FLAC__StreamMetadata *m[num_blocks];
        for(unsigned i=0; i<num_blocks; i++){
          m[i] = const_cast< ::FLAC__StreamMetadata* >((const ::FLAC__StreamMetadata*) metadata[i]);
        }
        return (bool) ::FLAC__stream_encoder_set_metadata(hark_flac_encoder, m, num_blocks);
////#endif
      }
      
      //// Getter
      State get_state() const
      {
        HARK_ASSERT(is_valid());
        return State(::FLAC__stream_encoder_get_state(hark_flac_encoder));
      }
      Decoder::Stream::State get_verify_decoder_state() const
      {
        HARK_ASSERT(is_valid());
        return Decoder::Stream::State(::FLAC__stream_encoder_get_verify_decoder_state(hark_flac_encoder));
      }
      void get_verify_decoder_error_stats(FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_verify_decoder_error_stats(hark_flac_encoder, absolute_sample, frame_number, channel, sample, expected, got);
      }
      bool get_verify() const
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_get_verify(hark_flac_encoder);
      }
      bool get_streamable_subset() const
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_get_streamable_subset(hark_flac_encoder);
      }
      bool get_do_mid_side_stereo() const
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_get_do_mid_side_stereo(hark_flac_encoder);
      }
      bool get_loose_mid_side_stereo() const
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_get_loose_mid_side_stereo(hark_flac_encoder);
      }
      unsigned get_channels() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_channels(hark_flac_encoder);
      }
      unsigned get_bits_per_sample() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_bits_per_sample(hark_flac_encoder);
      }
      unsigned get_sample_rate() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_sample_rate(hark_flac_encoder);
      }
      unsigned get_blocksize() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_blocksize(hark_flac_encoder);
      }
      unsigned get_max_lpc_order() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_max_lpc_order(hark_flac_encoder);
      }
      unsigned get_qlp_coeff_precision() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_qlp_coeff_precision(hark_flac_encoder);
      }
      bool get_do_qlp_coeff_prec_search() const
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_get_do_qlp_coeff_prec_search(hark_flac_encoder);
      }
      bool get_do_escape_coding() const
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_get_do_escape_coding(hark_flac_encoder);
      }
      bool get_do_exhaustive_model_search() const
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_get_do_exhaustive_model_search(hark_flac_encoder);
      }
      unsigned get_min_residual_partition_order() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_min_residual_partition_order(hark_flac_encoder);
      }
      unsigned get_max_residual_partition_order() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_max_residual_partition_order(hark_flac_encoder);
      }
      unsigned get_rice_parameter_search_dist() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_rice_parameter_search_dist(hark_flac_encoder);
      }
      FLAC__uint64 get_total_samples_estimate() const
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_get_total_samples_estimate(hark_flac_encoder);
      }
      
      //// initialize
      ::FLAC__StreamEncoderInitStatus init()
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_init_stream(hark_flac_encoder, write_callback_, seek_callback_, tell_callback_, metadata_callback_, /*client_data=*/(void*) this);
      }
      ::FLAC__StreamEncoderInitStatus init_ogg()
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_init_ogg_stream(hark_flac_encoder, read_callback_, write_callback_, seek_callback_, tell_callback_, metadata_callback_, /*client_data=*/(void*) this);
      }
      
      bool finish()
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_finish(hark_flac_encoder);
      }
      
      bool process(const FLAC__int32 * const buffer[], unsigned samples)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_process(hark_flac_encoder, buffer, samples);
      }
      bool process_interleaved(const FLAC__int32 buffer[], unsigned samples)
      {
        HARK_ASSERT(is_valid());
        return (bool) ::FLAC__stream_encoder_process_interleaved(hark_flac_encoder, buffer, samples);
      }
      
    protected:
      //// callback
      virtual ::FLAC__StreamEncoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes)
      {
        (void) buffer, (void) bytes;
        return ::FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED;
      }
      virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame) = 0;
////      ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC_byte buffer[], size_t bytes, unsigned samples, unsigned current_frame)
////      {
////        (void) buffer, (void) bytes, (void) samples, (void) current_frame;
////        return ::FLAC__STREAM_ENCODER_WRITE_STATUS_UNSUPPORTED;
////      }
      virtual ::FLAC__StreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset)
      {
        (void) absolute_byte_offset;
        return ::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
      }
      virtual ::FLAC__StreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset)
      {
        (void) absolute_byte_offset;
        return ::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
      }
      virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata)
      {
        (void) metadata;
      }
      
#if (defined _MSC_VER) || (defined __BORLANDC__) || (defined __GNUG__ && (__GNUG__ < 2 || (__GNUG__ == 2 && __GNUC_MINOR__ < 96))) || (defined __SUNPRO_CC)
      // lame hack: some MSVC/GCC versions can't see a protected encoder_ from nested State::resolved_as_cstring()
      friend State;
#endif
      ::FLAC__StreamEncoder *hark_flac_encoder;
      
      static ::FLAC__StreamEncoderReadStatus read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
      {
        (void) encoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->read_callback(buffer, bytes);
      }
      static ::FLAC__StreamEncoderWriteStatus write_callback_(const ::FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
      {
        (void) encoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->write_callback(buffer, bytes, samples, current_frame);
      }
      static ::FLAC__StreamEncoderSeekStatus seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
      {
        (void) encoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->seek_callback(absolute_byte_offset);
      }
      static ::FLAC__StreamEncoderTellStatus tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
      {
        (void) encoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->tell_callback(absolute_byte_offset);
      }
      static void metadata_callback_(const FLAC__StreamEncoder *encoder, const ::FLAC__StreamMetadata *metadata, void *client_data)
      {
        (void) encoder;
        HARK_ASSERT(0 != client_data);
        Stream *instance = reinterpret_cast<Stream *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->metadata_callback(metadata);
      }
    private:
      Stream(const Stream &);
      void operator=(const Stream &);
    }; // [HARK_FLAC::Encoder::Stream] class Stream is end
    class File: public Stream {
    public:
      File(): Stream(){ }
      ~File(){ }
      ::FLAC__StreamEncoderInitStatus init(FILE *file)
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_init_FILE(hark_flac_encoder, file, progress_callback_, /*client_data=*/(void*) this);
      }
      ::FLAC__StreamEncoderInitStatus init(const char *filename)
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_init_file(hark_flac_encoder, filename, progress_callback_, /*client_data=*/(void*) this);
      }
      ::FLAC__StreamEncoderInitStatus init(const std::string &filename)
      {
        return init(filename.c_str());
      }
      ::FLAC__StreamEncoderInitStatus init_ogg(FILE *file)
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_init_ogg_FILE(hark_flac_encoder, file, progress_callback_, /*client_data=*/(void*) this);
      }
      ::FLAC__StreamEncoderInitStatus init_ogg(const char *filename)
      {
        HARK_ASSERT(is_valid());
        return ::FLAC__stream_encoder_init_ogg_file(hark_flac_encoder, filename, progress_callback_, /*client_data=*/(void*) this);
      }
      ::FLAC__StreamEncoderInitStatus init_ogg(const std::string &filename)
      {
        return init_ogg(filename.c_str());
      }
      
    protected:
      //// callback
      virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame)
      {
        (void) buffer, (void) bytes, (void) samples, (void) current_frame;
        HARK_ASSERT(false);
        return ::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
      }
      virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_written)
      {
        (void) bytes_written, (void) samples_written, (void) frames_written, (void) total_frames_written;
      }
    private:
      static void progress_callback_(const ::FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_written, void *client_data)
      {
        (void) encoder;
        HARK_ASSERT(0 != client_data);
        File *instance = reinterpret_cast<File *>(client_data);
        HARK_ASSERT(0 != instance);
        return instance->progress_callback(bytes_written, samples_written, frames_written, total_frames_written);
      }
      File(const Stream &);
      void operator=(const Stream &);
    }; // [HARK_FLAC::Encoder::File] class File is end
  } // [HARK_FLAC::Encoder] namespace Encoder is end
  
  namespace RequestServer {
    // encoder implements for HARK
    // for Encode to Stream
    class StreamEncoder: public Encoder::Stream {
    public:
      StreamEncoder(): Encoder::Stream()
      {
        frame_count=0;
        offset=0;
      }
      ~StreamEncoder()
      {
      }
      size_t get_buffer(std::vector<FLAC__byte>& return_address, int timeout=10, size_t request_size=0, bool force=false){
        if(request_size == 0){ // 1-time request
          size_t prev_frame = frame_count;
          for(int t=0; t<timeout; t++){ usleep(100); if(prev_frame!=frame_count){ t=0; prev_frame = frame_count; } }
          size_t read_size = m_compressed_data.size();
          return_address.reserve(read_size);
          return_address.assign(m_compressed_data.begin(), m_compressed_data.end());
          return read_size;
        }
        else{ // constant size request for stream (if you request last frame use force option)
          size_t read_size = ((m_compressed_data.size() - offset) >= request_size ? request_size : (force ? (m_compressed_data.size() - offset) : 0));
          if(read_size != 0){
            std::vector<FLAC__byte>::iterator it_b = m_compressed_data.begin(); it_b += offset;
            std::vector<FLAC__byte>::iterator it_e = it_b; it_e += read_size;
            return_address.reserve(read_size);
            return_address.assign(it_b, it_e);
            offset+=read_size;
          }
          return read_size;
        }
      }
    protected:
      ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame)
      {
        //std::copy(buffer, buffer + bytes, std::back_inserter(m_compressed_data));
        std::vector<FLAC__byte> tmpvec(bytes);
        tmpvec.assign(buffer, buffer+bytes);
        m_compressed_data.insert(m_compressed_data.end(), tmpvec.begin(), tmpvec.end());
        frame_count++;
        //[DEBUG code]
        //std::cerr << "DUMP buffer:" << std::endl << buffer << std::endl;
        //std::cerr << "DUMP tmpvec:" << std::endl << std::string((char *)&tmpvec[0]) << std::endl;
        //std::cerr << "encoded data size: " << m_compressed_data.size() << std::endl;
        //std::cerr << "encoded frame count: " << frame_count << std::endl;
        //std::cerr << "encoded data:" << std::endl;
        //for(std::vector<FLAC__byte>::iterator it=m_compressed_data.begin(); it<m_compressed_data.end(); it++){
        //  std::cerr << std::hex << std::setw(2) << ((int) *it & 0xff) << " ";
        //}
        //std::cerr << std::dec << std::endl;
        return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
      }
    private:
      std::vector<FLAC__byte> m_compressed_data;
      size_t frame_count;
      size_t offset;
    }; // [HARK_FLAC::RequestServer::StreamEncoder] class StreamEncoder is end
    // for Encode to File
    class FileEncoder: public Encoder::File {
    public:
    protected:
    private:
    }; // [HARK_FLAC::RequestServer::FileEncoder] class FileEncoder is end
    class EncodeServer {
    private:
      StreamEncoder *m_encoder;
      //Metadata::VorbisComment lll;
      size_t m_remaining_samples;
      size_t m_encode_block_size;
      ////size_t m_frame_count;
      bool m_finished; // this flag is data received finished. if you want to get encode finished, confirm m_remaining_samples is 0.
      ////pthread_t th;
      
      int m_lv;
      int m_ch;
      int m_sr;
      int m_bits;
      int m_bytes_per_sample;
      int m_blocksize;
      
      std::queue<FLAC__int32> m_queue_buffer;
      
      FLAC__StreamMetadata *m_metadata[2];
      FLAC__StreamMetadata_VorbisComment_Entry m_entry;
    public:
      //Constructor
      EncodeServer():
        m_remaining_samples(0),
        m_encode_block_size(1024),
        ////m_frame_count(0),
        m_finished(false),
        m_lv(5),
        m_ch(1),
        m_sr(16000),
        m_bits(24),
        m_bytes_per_sample(3),
        m_blocksize(4096)
      {
        m_metadata[0]=0;
        m_metadata[1]=0;
        m_encoder = new StreamEncoder();
        if(m_encoder == 0 || !m_encoder->is_valid()){  std::cerr << "Could not create new encoder." << std::endl; }
        ////pthread_create(&th, 0, this->worker_write, reinterpret_cast<void*>(this));
      }

      ////static void *worker_write(void *arg){
      ////  while(1){
      ////    write_buffer();
      ////  }
      ////}
      //Destructor
      ~EncodeServer()
      {
        ////pthread_cancel(th);
        ////pthread_join(th, 0);
        if(m_metadata[0] != 0){
          FLAC__metadata_object_delete(m_metadata[0]);
        }
        if(m_metadata[1] != 0){
          FLAC__metadata_object_delete(m_metadata[1]);
        }
      }
      
      // [case1] (not stream processing like)
      //   new => set_encode_mode => request_encode(loop) => [request_encode(finish)] => set_metadata => start => stop => get_encoded_flac => delete
      // [case2] (stream processing, but get not stream like encoded data) 
      //   new => set_encode_mode => set_metadata => start => request_encode(loop) => [request_encode(finish)] => stop => get_encoded_flac => delete
      // [case3] (stream processing and get stream encoding data)
      //   new => set_encode_mode => set_metadata => start => request_encode + get_encoded_flac(loop:request_size) => [request_encode(finish:request_size)] => stop => get_encoded_flac(remaining_size) => delete

      void set_encode_mode(int comp_level, int channels, int sampling_rate, int bits_per_sample, int blocksize){
        m_lv = comp_level; m_ch = channels; m_sr = sampling_rate; m_bits = bits_per_sample; m_blocksize = blocksize;
      }

      void start(){
        FLAC__StreamEncoderInitStatus istatus;
        if(m_encoder != 0 && m_encoder->is_valid()){
          if(!m_encoder->set_verify(true)){            std::cerr << "Could not set verify." << std::endl; }
          if(!m_encoder->set_compression_level(m_lv)){ std::cerr << "Could not set compression level." << std::endl; }
          if(!m_encoder->set_channels(m_ch)){          std::cerr << "Could not set number of channels." << std::endl; }
          if(!m_encoder->set_sample_rate(m_sr)){       std::cerr << "Could not set sample rate." << std::endl; }
          if(!m_encoder->set_bits_per_sample(m_bits)){ std::cerr << "Could not set bits per sample." << std::endl; }
          if(!m_encoder->set_blocksize(m_blocksize)){  std::cerr << "Could not set blocksize." << std::endl; }
          m_bytes_per_sample = m_bits / 8;
        }
        else{
          std::cerr << "The encoder was invalid." << std::endl;
        }
        if((istatus = m_encoder->init()) != FLAC__STREAM_ENCODER_INIT_STATUS_OK){ std::cerr << "Could not initialize encoder" << istatus << std::endl; }
      }
      void stop(){
        m_finished=true;
        while(m_remaining_samples!=0){ write_buffer(); }
        std::cerr << "END" << std::endl;
        if(!m_encoder->finish()){
          std::cerr << "encoder finish failed" << std::endl;
        }
      }
      
      // Called native C function in this method for easy cording. [CAUTION] You are must not using NULL macro in C++, you can use 0 instead.
      bool set_metadata(std::map<std::string, std::string> metadata_map){
        if(m_encoder->is_valid()){
          if(m_metadata[0] != 0){
            FLAC__metadata_object_delete(m_metadata[0]);
          }
          if(m_metadata[1] != 0){
            FLAC__metadata_object_delete(m_metadata[1]);
          }
          if((m_metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == 0 ||
             (m_metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == 0){
            std::cerr << "Could not create new metadata object." << std::endl;
            return false;
          }
          else{
            std::map<std::string, std::string>::iterator it = metadata_map.begin();
            while(it != metadata_map.end()){
              if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&m_entry, (it->first).c_str(), (it->second).c_str()) ||
                 !FLAC__metadata_object_vorbiscomment_append_comment(m_metadata[0], m_entry, /*copy=*/false)){
                std::cerr << "Could not set or invalid metadata(tag:" << it->first << ", vorbiscomment:" << it->second << ")." << std::endl;
                return false;
              }
              it++;
            }
            m_metadata[1]->length = 1024; // set the padding length (libFLAC++ sample code is set to 1234, however "must be a multiple of 8" is written by flac format specification.)
            if(!m_encoder->set_metadata(m_metadata, 2)){ // 2 is num of blocks (2 blocks : vorbiscomments, padding)
              std::cerr << "Could not set metadata to encoder." << std::endl;
              return false;
            }
            return true;
          }
          std::cerr << "Bug!! this is unreachable point." << std::endl;
          return false; // unreachable
        }
        else{
          std::cerr << "Could not found valid encoder. Please, (re)create new encoder." << std::endl;
          return false;
        }
        std::cerr << "Bug!! this is unreachable point." << std::endl;
        return false; // unreachable
      }
      
      // interleaved flag is following definition of data order. (s is sample, c is channel)
      // true : [(s1c1, s1c2, ... s1cM-1, s1cM), (s2c1, s2c2, ... s2cM-1, s2cM), ... (sNc1, sNc2, ... sNcM-1, sNcM)]
      // false: [(s1c1, s2c1, ... sN-1c1, sNc1), (s1c2, s2c2, ... sN-1c2, sNc2), ... (s1cM, s2cM, ... sN-1cM, sNcM)]
      // pcm_samples is num of sample. sizeof(pcm_data) == sizeof(pcm_data[0]) * pcm_length * m_ch
      // finish flag tells the encoder that it is the last request.
      bool request_encode(std::string pcm_data, size_t pcm_samples, bool finish=false, bool interleaved=true){
        if(m_encoder->is_valid()){
          if(pcm_data.size() != (pcm_samples * m_ch * m_bytes_per_sample)){
            std::cerr << "Request PCM size missmatch : (pcm_data.size()=" << pcm_data.size() << ", pcm_samples * m_ch * m_bytes_per_sample=" << pcm_samples << "*" << m_ch << "*" << m_bytes_per_sample << "=" << pcm_samples * m_ch * m_bytes_per_sample << ")" << std::endl;
            return false;
          }
          size_t pcm_length = pcm_samples * m_ch;
          char in_pcm[pcm_data.size()+1]; in_pcm[pcm_data.size()] = 0;
          FLAC__int32 out_pcm[pcm_length];
          size_t i, j, k;
          std::memcpy(in_pcm, pcm_data.c_str(), pcm_data.size());
          if(interleaved){
            switch(m_bytes_per_sample){
            case 1:
              for(i=0; i<pcm_length; i++){
                out_pcm[i] = (FLAC__int32) in_pcm[i];
              }
              break;
            case 2:
              for(i=0; i<pcm_length; i++){
                out_pcm[i] = (FLAC__int32) ( (((FLAC__int16)in_pcm[2*i+1]) << 8) | ((FLAC__int16)(unsigned char)in_pcm[2*i]) );
              }
              break;
            case 3:
            default:
              for(i=0; i<pcm_length; i++){
                out_pcm[i] = (FLAC__int32) ( (((FLAC__int32)in_pcm[3*i+2]) << 16) | ((FLAC__int32)((unsigned char)in_pcm[3*i+1]) << 8) | ((FLAC__int32)((unsigned char)in_pcm[3*i])) );
              }
              break;
            }
          }
          else{
            //char tmp[pcm_data.size()] = pcm_data.c_str();
            switch(m_bytes_per_sample){
            case 1:
              for(i=0, k=0; i<pcm_samples; i++){
                for(j=0; j<m_ch; j++){
                  out_pcm[k++] = (FLAC__int32) in_pcm[j*pcm_samples+i];
                }
              }
              break;
            case 2:
              for(i=0, k=0; i<pcm_samples; i++){
                for(j=0; j<m_ch; j++){
                  out_pcm[k++] = (FLAC__int32) ( (((FLAC__int16)in_pcm[2*(j*pcm_samples+i)+1]) << 8) | ((FLAC__int16)(unsigned char)in_pcm[2*(j*pcm_samples+i)]) );
                }
              }
              break;
            case 3:
            default:
              for(i=0, k=0; i<pcm_samples; i++){
                for(j=0; j<m_ch; j++){
                  out_pcm[k++] = (FLAC__int32) ( (((FLAC__int32)in_pcm[3*(j*pcm_samples+i)+2]) << 16) | ((FLAC__int32)((unsigned char)in_pcm[3*(j*pcm_samples+i)+1]) << 8) | ((FLAC__int32)((unsigned char)in_pcm[3*(j*pcm_samples+i)])) );
                }
              }
              break;
            }
          }
          i=0; while(i<pcm_data.size()){ m_queue_buffer.push(out_pcm[i++]); }
          m_remaining_samples += pcm_samples;
          m_finished = finish;
          write_buffer();
          ////m_frame_count++;
          return true;
        }
        else{
          std::cerr << "Could not found valid encoder. Please, (re)create new encoder." << std::endl;
          return false;
        }
        std::cerr << "Bug!! this is unreachable point." << std::endl;
        return false; // unreachable
      }
      bool request_encode(std::vector<float> pcm_data, size_t pcm_samples, bool finish=false, bool interleaved=true, bool limitcheck=true){
        if(m_encoder->is_valid()){
          if(pcm_data.size() != (pcm_samples * m_ch)){
            std::cerr << "Request PCM size missmatch : (pcm_data.size()=" << pcm_data.size() << ", pcm_samples * m_ch=" << pcm_samples << "*" << m_ch << "=" << pcm_samples * m_ch << ")" << std::endl;
            return false;
          }
          FLAC__int32 out_pcm[pcm_data.size()];
          float tmp_pcm;
          size_t i, j, k;
          if(limitcheck){
            /*FLAC__int32*/ float max_val, min_val;
            switch(m_bytes_per_sample){
            case 1:
              max_val = (float)SCHAR_MAX;
              min_val = (float)SCHAR_MIN;
              break;
            case 2:
              max_val = (float)SHRT_MAX;
              min_val = (float)SHRT_MIN;
              break;
            case 3:
            default:
              max_val = (float)((((float)SHRT_MAX + 1) * ((float)UCHAR_MAX + 1)) - 1);
              min_val = (float)(-((float)SHRT_MAX + 1) * ((float)UCHAR_MAX + 1));
              break;
            }
            if(interleaved){
              for(i=0; i<pcm_data.size(); i++){
                out_pcm[i] = (FLAC__int32)(pcm_data[i] >= max_val ? max_val : (pcm_data[i] <= min_val ? min_val : pcm_data[i]));
              }
            }
            else{
              for(i=0, k=0; i<pcm_samples; i++){
                for(j=0; j<m_ch; j++){
                  tmp_pcm = pcm_data[j*pcm_samples+i];
                  out_pcm[k++] = (FLAC__int32)(tmp_pcm >= max_val ? max_val : (tmp_pcm <= min_val ? min_val : tmp_pcm));
                }
              }
            }
          }
          else{
            if(interleaved){
              for(i=0; i<pcm_data.size(); i++){ out_pcm[i] = (FLAC__int32) pcm_data[i]; }
            }
            else{
              for(i=0, k=0; i<pcm_samples; i++){
                for(j=0; j<m_ch; j++){ out_pcm[k++] = (FLAC__int32) pcm_data[j*pcm_samples+i]; }
              }
            }
          }
          i=0; while(i<pcm_data.size()){ m_queue_buffer.push(out_pcm[i++]); }
          m_remaining_samples += pcm_samples;
          m_finished = finish;
          write_buffer();
          ////m_frame_count++;
          return true;
        }
        else{
          std::cerr << "Could not found valid encoder. Please, (re)create new encoder." << std::endl;
          return false;
        }
        std::cerr << "Bug!! this is unreachable point." << std::endl;
        return false; // unreachable
      }
      
      inline bool is_finished(){ return (m_finished && (m_remaining_samples==0)); }
      
      std::vector<unsigned char> get_encoded_flac(int req_size=0, bool force=false){
        std::vector<FLAC__byte> read_buffer(0);
        m_encoder->get_buffer(read_buffer, 10/*timeout*/, req_size, force);
        //[DEBUG code]
        //std::cerr << "encoded data size: " << read_buffer.size() << std::endl;
        //std::cerr << "encoded data:" << std::endl;
        //for(std::vector<FLAC__byte>::iterator it=read_buffer.begin(); it<read_buffer.end(); it++){
        //  std::cerr << std::hex << std::setw(2) << ((int) *it & 0xff) << " ";
        //}
        //std::cerr << std::dec << std::endl;
        return read_buffer;
      }
    protected:
      void write_buffer(){
        if(m_remaining_samples > 0){
          size_t block_size = (m_remaining_samples >= m_encode_block_size ? m_encode_block_size : (m_finished ? m_remaining_samples : 0));
          //std::cerr << block_size << " " << m_remaining_samples << " " << m_encode_block_size << std::endl;
          if(block_size != 0){
            FLAC__int32 read_buffer[block_size*m_ch];
            size_t i = 0;
            while(i<(block_size*m_ch) && !m_queue_buffer.empty()){
              read_buffer[i] = m_queue_buffer.front(); m_queue_buffer.pop(); i++;
            }
            //if(m_encoder->is_valid()){ std::cerr << "encoder valid" << std::endl; }
            if(!m_encoder->process_interleaved(read_buffer, block_size)){
              std::cerr << "process interleaved error [read_buffer (address)]" << read_buffer << " [block_size]" << block_size << std::endl;
            }
            //else{
            //  std::cerr << "process interleaved success [read_buffer (address)]" << read_buffer << " [block_size]" << block_size << std::endl;
            //}
            m_remaining_samples -= block_size;
          }
        }
      }
    }; // [HARK_FLAC::RequestServer::EncodeServer] class Encoder is end
    
    // for Decode from Stream
    class StreamDecoder: public Decoder::Stream {
    public:
      StreamDecoder() : Decoder::Stream()
      {
        m_interleaved = 1;
        m_sr = 16000;
        m_ch = 1;
        m_bits = 16;
        m_max_blocksize = 65536;
        m_required_buffer_size = 2048;
        metadata_received = 0;
        frame_count=0;
        read_offset=0;
        write_offset=0;
        finished=0;
        input_finished=0;
      }
      ~StreamDecoder()
      {
      }

      size_t get_offset(){ return write_offset; }
      bool set_offset(size_t offset){
        //[DEBUG code]
        //std::cerr << "[DEBUG] set_offset():\n"
        //             "        offset updated: from " << write_offset << " to " << offset << std::endl;
        write_offset = offset;
        return true;
      }

      //bool buffer_is_not_empty(){ return (m_compressed_data_buffer.size() - write_offset - (input_finished ? 0 : m_max_blocksize * ((m_ch==0)?1:m_ch))) > 0; }
      //bool buffer_is_not_empty(){ return (m_compressed_data_buffer.size() - write_offset) != 0; }
      bool buffer_is_not_empty(){ return m_compressed_data_buffer.size() > write_offset + m_required_buffer_size; }
      //bool buffer_is_not_empty(){ return m_compressed_data_buffer.size() > write_offset + 65536; }
      //bool buffer_is_not_empty(){ return m_compressed_data_buffer.size() > write_offset + 49152; }
      //std::vector<int> buffer_is_not_empty(){ std::vector<int> v(2); v[0] = m_compressed_data_buffer.size(); v[1] = write_offset; return v; }

      size_t get_bufsize(){ return m_compressed_data_buffer.size(); }

      void set_buffer(std::vector<FLAC__byte>& flac_data, size_t data_szie, bool finish=false){
        m_compressed_data_buffer.insert(m_compressed_data_buffer.end(), flac_data.begin(), flac_data.end());
      }
      size_t get_buffer(std::vector<FLAC__int32>& return_address, int timeout=10, size_t request_size=0, bool force=false, int advance=0){
        if(request_size == 0){ // 1-time request
          size_t prev_frame = frame_count;
          for(int t=0; t<timeout; t++){ usleep(100); if(prev_frame!=frame_count){ t=0; prev_frame = frame_count; } }
          //while(!finished){ usleep(100); }
          size_t read_size = m_decompressed_data.size();
          return_address.reserve(read_size);
          return_address.assign(m_decompressed_data.begin(), m_decompressed_data.end());
          return read_size;
        }
        else if(advance == 0){ // constant size request for stream (if you request last frame use force option)
          size_t read_size = ((m_decompressed_data.size() - read_offset) >= request_size ? request_size : (force ? (m_decompressed_data.size() - read_offset) : 0));
          if(read_size != 0){
            std::vector<FLAC__int32>::iterator it_b = m_decompressed_data.begin(); it_b += read_offset;
            std::vector<FLAC__int32>::iterator it_e = it_b; it_e += read_size;
            return_address.reserve(read_size);
            return_address.assign(it_b, it_e);
            read_offset+=read_size;
          }
          return read_size;
        }
        else{ // constant size request for stream (if you request last frame use force option)
          size_t read_size = (m_decompressed_data.size() >= request_size ? request_size : (force ? m_decompressed_data.size() : 0));
          if(read_size != 0){
            std::vector<FLAC__int32>::iterator it_b = m_decompressed_data.begin();
            std::vector<FLAC__int32>::iterator it_e = it_b; it_e += read_size;
            return_address.reserve(read_size);
            return_address.assign(it_b, it_e);

            std::vector<FLAC__int32>::iterator it_a = it_b; it_a += force ? read_size : advance;
            m_decompressed_data.erase(it_b, it_a);
          }
          return read_size;
        }
      }
      size_t get_metadata(std::map<std::string, std::string>& return_metadata){
        size_t num_metadata = 0;
        std::map<std::string, std::string>::iterator it=m_vorbis_comments.begin();
        while(it != m_vorbis_comments.end()){
          return_metadata[it->first] = it->second;
          it++; num_metadata++;
        }
        return num_metadata;
      }
      int is_finished(){ return finished; }

      void set_input_finished(){ input_finished = 1; }
      void unset_input_finished(){ input_finished = 0; }
      int is_input_finished(){ return input_finished; }
    protected:
/*
      ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes)
      {
        size_t expected_bytes = *bytes;
        size_t actual_read_bytes = ((m_compressed_data_buffer.size() - write_offset) < expected_bytes) ? (m_compressed_data_buffer.size() - write_offset) : expected_bytes;
        *bytes = actual_read_bytes;
        std::vector<FLAC__byte> tmpvec(actual_read_bytes);
        std::vector<FLAC__byte>::iterator it_b = m_compressed_data_buffer.begin(); it_b+=write_offset;
        std::vector<FLAC__byte>::iterator it_e = it_b; it_e+=actual_read_bytes;
        tmpvec.assign(it_b, it_e);
        memcpy(buffer, &tmpvec[0], tmpvec.size());
        //[same as ..., but not safety code] memcpy(buffer, &m_compressed_data_buffer[write_offset], actual_read_bytes);
        write_offset+=actual_read_bytes;
        //finished = (actual_read_bytes == 0) ? 1 : 0;
        finished = (actual_read_bytes == 0) ? input_finished : 0;
        //[DEBUG code]
        //std::cerr << "read call back" << std::endl;
        std::cerr << "[DEBUG] expected_bytes: " << expected_bytes
                  <<       ", actual_read_bytes: " << actual_read_bytes << "\n"
                  <<         "m_compressed_data_buffer.size(): " << m_compressed_data_buffer.size()
                  <<       ", write_offset: " << write_offset << std::endl;

        //return (actual_read_bytes == 0) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
        return (input_finished == 1 && actual_read_bytes == 0) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
      }
*/

////
/*
      ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes)
      {
        size_t expected_bytes = *bytes;
        //size_t actual_read_bytes = ((m_compressed_data_buffer.size() - write_offset) < expected_bytes) ? (input_finished == 1 ? (m_compressed_data_buffer.size() - write_offset) : 0) : expected_bytes;
        //size_t actual_read_bytes = ((m_compressed_data_buffer.size() - write_offset) < expected_bytes) ? (m_compressed_data_buffer.size() - write_offset) : expected_bytes;
        size_t actual_read_bytes = ((m_compressed_data_buffer.size() - write_offset) < expected_bytes) ? (input_finished == 1 ? (m_compressed_data_buffer.size() - write_offset) : 0) : expected_bytes;
        *bytes = actual_read_bytes;
        std::vector<FLAC__byte> tmpvec(actual_read_bytes);
        std::vector<FLAC__byte>::iterator it_b = m_compressed_data_buffer.begin(); it_b+=write_offset;
        std::vector<FLAC__byte>::iterator it_e = it_b; it_e+=actual_read_bytes;
        tmpvec.assign(it_b, it_e);
        memcpy(buffer, &tmpvec[0], tmpvec.size());
        //[same as ..., but not safety code] memcpy(buffer, &m_compressed_data_buffer[write_offset], actual_read_bytes);
        write_offset+=actual_read_bytes;
        //finished = (actual_read_bytes == 0) ? 1 : 0;
        finished = (actual_read_bytes == 0) ? input_finished : 0;
        //[DEBUG code]
        //std::cerr << "read call back" << std::endl;
        std::cerr << "[DEBUG] expected_bytes: " << expected_bytes
                  <<       ", actual_read_bytes: " << actual_read_bytes << "\n"
                  << "        m_compressed_data_buffer.size(): " << m_compressed_data_buffer.size()
                  <<       ", write_offset: " << write_offset << std::endl;

        //return (actual_read_bytes == 0) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
        return (actual_read_bytes == 0) ? (finished == 1 ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_ABORT) : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
      }
*/
////
      ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes)
      {
        size_t expected_bytes = *bytes;
        size_t actual_read_bytes = ((m_compressed_data_buffer.size() - write_offset) < expected_bytes) ? (m_compressed_data_buffer.size() - write_offset) : expected_bytes;
        *bytes = actual_read_bytes;
        if(actual_read_bytes != 0){
          std::vector<FLAC__byte> tmpvec(actual_read_bytes);
          std::vector<FLAC__byte>::iterator it_b = m_compressed_data_buffer.begin(); it_b+=write_offset;
          std::vector<FLAC__byte>::iterator it_e = it_b; it_e+=actual_read_bytes;
          tmpvec.assign(it_b, it_e);
          memcpy(buffer, &tmpvec[0], tmpvec.size());
          //[same as ..., but not safety code] memcpy(buffer, &m_compressed_data_buffer[write_offset], actual_read_bytes);
          write_offset+=actual_read_bytes;
        }
        //finished = (actual_read_bytes == 0) ? 1 : 0;
        finished = (actual_read_bytes == 0) ? input_finished : 0;
        //[DEBUG code]
        //std::cerr << "[DEBUG] read_callback():\n"
        //             "        expected_bytes: " << expected_bytes << "\n"
        //             "        actual_read_bytes: " << actual_read_bytes << "\n"
        //             "        m_compressed_data_buffer.size(): " << m_compressed_data_buffer.size() << "\n"
        //             "        write_offset: " << write_offset << std::endl;
        return (actual_read_bytes == 0) ? (finished == 1 ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_ABORT) : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
      }

      ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
      {
        size_t block_size = frame->header.blocksize;
        size_t channels   = frame->header.channels;
        size_t length     = block_size * channels;
        size_t ch, sample, index;
        if(m_interleaved){
          FLAC__int32 serial_buffer[length];
          for(sample=0, index=0; sample<block_size; sample++){
            for(ch=0; ch<channels; ch++){
              serial_buffer[index++] = buffer[ch][sample];
            }
          }
          std::vector<FLAC__int32> tmpvec(length);
          tmpvec.assign(serial_buffer, serial_buffer+length);
          m_decompressed_data.insert(m_decompressed_data.end(), tmpvec.begin(), tmpvec.end());
        }
        else{
          if(frame->header.number.sample_number!=0){
            for(ch=0; ch<channels; ch++){
              std::vector<FLAC__int32> tmpvec(block_size);
              tmpvec.assign(buffer[ch], buffer[ch]+block_size);
              m_decompressed_data_map[ch].insert(m_decompressed_data_map[ch].end(), tmpvec.begin(), tmpvec.end());
            }
          }
          else{ // if first frame, assign, otherwise insert. NOTE: FLAC stream was NOT support dynamic channel change.
            for(ch=0; ch<channels; ch++){
              std::vector<FLAC__int32> tmpvec(block_size);
              tmpvec.assign(buffer[ch], buffer[ch]+block_size);
              m_decompressed_data_map[ch].assign(tmpvec.begin(), tmpvec.end());
            }
          }
        }
        //[DEBUG code]
        //std::cerr << "[DEBUG] write_callback():\n"
        //             "        frame->header.number.sample_number: " << frame->header.number.sample_number << "\n"
        //             "        frame->header.number.frame_number: " << frame->header.number.frame_number << "\n"
        //             "        frame->header.blocksize: " << frame->header.blocksize << "\n"
        //             "        frame->header.channels: " << frame->header.channels << "\n"
        //             "        frame->header.bits_per_sample: " << frame->header.bits_per_sample
        //          << std::endl;
        return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
      }
      void metadata_callback(const ::FLAC__StreamMetadata *metadata)
      {
        Metadata::VorbisComment vc(metadata); // VorbisComment structure is very complex
        switch(metadata->type){
        case FLAC__METADATA_TYPE_STREAMINFO:
            m_sr = metadata->data.stream_info.sample_rate;
            m_ch = metadata->data.stream_info.channels;
            m_bits = metadata->data.stream_info.bits_per_sample;
            m_max_blocksize = metadata->data.stream_info.max_blocksize;
            m_required_buffer_size = m_max_blocksize * m_ch;
            metadata_received = 1;
            //[DEBUG code]
            //std::cerr << "metadata streaminfo call back" << std::endl;
            std::cerr << "StreamInfo { SampleRate:[" << m_sr << "], Channels:[" << m_ch << "], BitsPerSample:[" << m_bits << "], MaxBlocksize:[" << m_max_blocksize << "] }" << std::endl;
          break;
        case FLAC__METADATA_TYPE_VORBIS_COMMENT:
            // index is always unsigned value, but loop termination index value is -1 for fast loop.
            for(int index=vc.get_num_comments()-1; index>=0; index--){
              Metadata::VorbisComment::Entry entry(vc.get_comment(index));
              std::string field_name(entry.get_field_name());
              std::string field_value(entry.get_field_value());
              m_vorbis_comments[field_name] = field_value;
              //[DEBUG code]
              //std::cerr << "VorbisCommentEntry { FieldName:[" << field_name << "], FieldValue[" << field_value << "] }" << std::endl;
            }
            //[DEBUG code]
            //std::cerr << "metadata vorbiscomment call back" << std::endl;
          break;
        //[no processing for quickly v-table search]
        //case FLAC__METADATA_TYPE_PADDING:
        //case FLAC__METADATA_TYPE_APPLICATION:
        //case FLAC__METADATA_TYPE_SEEKTABLE:
        //case FLAC__METADATA_TYPE_CUESHEET:
        //case FLAC__METADATA_TYPE_PICTURE:
        default:
          break;
        }
        //[DEBUG code]
        //std::cerr << "[DEBUG] metadata_callback():" << std::endl;
      }
      void error_callback(::FLAC__StreamDecoderErrorStatus status)
      {
        (void) status;
      }

      ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset)
      {
        //[DEBUG code]
        //std::cerr << "[DEBUG] seek_callback():\n"
        //             "        absolute_byte_offset: " << absolute_byte_offset << std::endl;
        write_offset = (size_t) absolute_byte_offset;
        finished = 0;
        return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
      }
      ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset)
      {
        (*absolute_byte_offset) = (FLAC__uint64) write_offset;
        //[DEBUG code]
        //std::cerr << "[DEBUG] tell_callback():\n"
        //             "        absolute_byte_offset: " << (*absolute_byte_offset) << std::endl;
        return FLAC__STREAM_DECODER_TELL_STATUS_OK;
      }
      ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length)
      {
        *stream_length = (FLAC__uint64) m_compressed_data_buffer.size();
        //[DEBUG code]
        //std::cerr << "[DEBUG] length_callback():\n"
        //             "        stream_length: " << (*stream_length) << std::endl;
        return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
      }
      bool eof_callback()
      {
        return (finished == 1) ? true : false;
      }

    private:
      int m_interleaved; // if 1 is set, interleave mode. if 0 is set, de-interleave mode (each channel).
      unsigned m_sr, m_ch, m_bits;
      size_t m_max_blocksize;
      size_t m_required_buffer_size;
      int metadata_received;
      std::vector<FLAC__byte> m_compressed_data_buffer;
      std::vector<FLAC__int32> m_decompressed_data; // interleaved data
      std::map<int, std::vector<FLAC__int32> > m_decompressed_data_map; // de-interleaved data for each channel map
      std::map<std::string, std::string> m_vorbis_comments;
      size_t frame_count;
      size_t write_offset;
      size_t read_offset;
      int finished;
      int input_finished;
    }; // [HARK_FLAC::RequestServer::StreamDecoder] class StreamDecoder is end
    // for Decode from File
    class FileDecoder: public Decoder::File {
    public:
      FileDecoder(FILE *file_name){}
    protected:
    }; // [HARK_FLAC::RequestServer::FileDecoder] class FileDecoder is end
    class DecodeServer {
    private:
      StreamDecoder *m_decoder;
    public:
      //Constructor
      DecodeServer()
      {
        prev_offset = 0;
        m_decoder = new StreamDecoder();
        if(m_decoder == 0 || !m_decoder->is_valid()){  std::cerr << "Could not create new encoder." << std::endl; }
        else{
          if(!m_decoder->set_md5_checking(false)){     std::cerr << "Could not set/unset MD5 cheking flag." << std::endl; }
          // please MUST call set_metadata_respond_all(),
          // because Source ID included on vorbis_comments type metadata,
          // but default setting respond streaminfo type metadata only.
          if(!m_decoder->set_metadata_respond_all()){  std::cerr << "Could not set metadata respond all." << std::endl; }
        }
      }
      
      //Destructor
      ~DecodeServer()
      {
      }
      
      // [case1] (not stream processing like)
      //   new => start => request_decode(once) => get_metadata => get_decoded_pcm(loop:request_size) => stop => delete
      // [case2] (stream processing, but get not stream like decoded data) 
      //   new => start => request_decode(loop) => [request_decode(finish)] => get_metadata => get_decoded_pcm(loop:request_size) => stop => delete
      // [case3] (stream processing and get stream decoding data)
      //   new => start => request_decode + get_metadata + get_decoded_pcm(loop:request_size) => [request_decode + get_metadata + get_decoded_pcm(finish:remaining_size)] => stop => delete
      void start(){
        FLAC__StreamDecoderInitStatus istatus;
        if((istatus = m_decoder->init()) != FLAC__STREAM_DECODER_INIT_STATUS_OK){ std::cerr << "Could not initialize decoder" << istatus << std::endl; }
      }
      void stop(){
        //m_finished=true;
        while(!m_decoder->is_finished()){ decode(true); }
        std::cerr << "END" << std::endl;
        if(!m_decoder->finish()){
          std::cerr << "decoder finish failed" << std::endl;
        }
      }

      void requst_decode(std::vector<unsigned char>& flac_data, size_t flac_bytes, bool finish=false) // [NOTE] typedef uint8_t FLAC__byte
      {
        m_decoder->set_buffer(flac_data, flac_bytes, finish);
        decode(finish);
      }
      
      size_t get_metadata(std::map<std::string, std::string>& metadata){
        return m_decoder->get_metadata(metadata);
      }

      int get_channels(){
        return (int) m_decoder->get_channels();
      }

      int get_bits_per_sample(){
        return (int) m_decoder->get_bits_per_sample();
      }

      int get_sampling_rate(){
        return (int) m_decoder->get_sample_rate();
      }

      std::vector<float> get_decoded_pcm(int req_size=0, int advance=0, bool force=false, bool interleaved=true, bool limitcheck=true){
        std::vector<FLAC__int32> read_buffer(0);
        m_decoder->get_buffer(read_buffer, 10/*timeout*/, req_size, force, advance);
        std::vector<float> return_buffer(read_buffer.size());
        for(int i=0; i<read_buffer.size(); i++){ return_buffer[i] = (float)read_buffer[i]; }
        //[DEBUG code]
        // std::cerr << "encoded data size: " << read_buffer.size() << std::endl;
        // std::cerr << "encoded data:" << std::endl;
        // for(std::vector<FLAC__byte>::iterator it=read_buffer.begin(); it<read_buffer.end(); it++){
        //  std::cerr << std::hex << std::setw(2) << ((int) *it & 0xff) << " ";
        // }
        // std::cerr << std::dec << std::endl;
        return return_buffer;
      }
    protected:
/*
      void decode(bool finish=false){
        // The FLAC decoder will be in END_OF_STREAM status if the buffer read fails,
        // and will not be able to input a new stream (cannot continue decoding).
        // Therefore, the buffer size must be monitored to stop the decoding request.
        while(m_decoder->buffer_is_not_empty()){
          m_decoder->process_single();
        }
        if(finish){
          // The "finish" argument is a flag that means that the stream input has been terminated.
          // Instead of monitoring the buffer size, decoding continues until the decoder status
          // is END_OF_STREAM. Otherwise, an undecoded FLAC frame will occur.
          do{
            m_decoder->process_single();
          } while(m_decoder->get_state() != FLAC__STREAM_DECODER_END_OF_STREAM);
        }
      }
*/
      // [DEBUG version]
      void decode(bool finish=false){
        if(finish){ m_decoder->set_input_finished(); }
        bool flag = true;
        Decoder::Stream::State s = m_decoder->get_state();
        //[DEBUG code]
        //std::cerr << "[DEBUG] FLAC decoder state(beginning of the function): "
        //          << s.as_cstring() << std::endl;

        if(s == FLAC__STREAM_DECODER_END_OF_STREAM){
          std::cerr << "[BUG] The state of this decoder is already END_OF_STREAM.\n"
                       "      However, a decode request has occurred.\n"
                       "      No matter how much you write to the stream buffer,\n"
                       "      it will never be read." << std::endl;
        }
      
        // The FLAC decoder will be in END_OF_STREAM status if the buffer read fails,
        // and will not be able to input a new stream (cannot continue decoding).
        // Therefore, the buffer size must be monitored to stop the decoding request.
        while(m_decoder->buffer_is_not_empty() && flag){
          //[DEBUG code]
          //std::cerr << "[DEBUG] FLAC decoder (buffer_is_not_empty()==true):\n"
          //             "        m_compressed_data_buffer.size(): " << m_decoder->get_bufsize() << "\n"
          //             "        write_offset: " << m_decoder->get_offset() << std::endl;
          //s = m_decoder->get_state();
          //std::cerr << "[DEBUG] FLAC decoder state(not finish:before): "
          //          << s.as_cstring() << std::endl;
          flag = m_decoder->process_single();
          //[DEBUG code]
          //std::cerr << "[DEBUG] FLAC decoder flag: " << (flag ? "True" : "False") << std::endl;
          s = m_decoder->get_state();
          //[DEBUG code]
          //std::cerr << "[DEBUG] FLAC decoder state(not finish:after): "
          //          << s.as_cstring() << std::endl;
          if(s == FLAC__STREAM_DECODER_ABORTED){
            ////m_decoder->seek_absolute(prev_offset); //// seek offset (libFLAC 1.3.1 is buggy)
            m_decoder->flush(); //// We need reset state [ABORT => SEARCH_FOR_FRAME_SYNC]
            m_decoder->set_offset(prev_offset); //// recover offset
            flag = false;
          }
          else if(s == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
               || s == FLAC__STREAM_DECODER_READ_METADATA
               || s == FLAC__STREAM_DECODER_END_OF_STREAM){
            prev_offset = m_decoder->get_offset(); //// backup offset
            flag = false;
          }
          else if(s == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC){
            prev_offset = m_decoder->get_offset(); //// backup offset
          }
          //[DEBUG code]
          //std::cerr << "[DEBUG] FLAC decoder flag: " << (flag ? "True" : "False") << std::endl;
        }
      
        if(finish){
          // The "finish" argument is a flag that means that the stream input has been terminated.
          // Instead of monitoring the buffer size, decoding continues until the decoder status
          // is END_OF_STREAM. Otherwise, an undecoded FLAC frame will occur.
          do{
            //[DEBUG code]
            //s = m_decoder->get_state();
            //std::cerr << "[DEBUG] FLAC deocder state(finish:before): "
            //          << s.as_cstring() << std::endl;
            flag = m_decoder->process_single();
            s = m_decoder->get_state();
            //[DEBUG code]
            //std::cerr << "[DEBUG] FLAC deocder state(finish:after): "
            //          << s.as_cstring() << std::endl;
          } while(s != FLAC__STREAM_DECODER_END_OF_STREAM);
        }
      }//
      size_t prev_offset;
    }; // [HARK_FLAC::RequestServer::DecodeServer] class DecodeServer is end
  } // [HARK_FLAC::RequestServer] namespace RequestServer is end
} // [HARK_FLAC] namespace HARK_FLAC is end

//#endif // ENABLE_FLAC

#ifdef PUBLISHER // bad work, will fix later.
  }
#else
  }
#endif

#endif // HARK_FLAC_BASE_HPP

