// file: $isip/class/io/Sof/Sof.h
// version: $Id: Sof.h 6805 2001-04-23 22:57:41Z peng $
//

// make sure definitions are only made once
//
#ifndef ISIP_SOF
#define ISIP_SOF

// isip include files
//
#ifndef ISIP_FILE
#include <File.h>
#endif

#ifndef ISIP_SOF_SYMBOL_TABLE
#include <SofSymbolTable.h>
#endif

#ifndef ISIP_SOF_LIST
#include <SofList.h>
#endif

#ifndef ISIP_CHECKSUM
#include <Checksum.h>
#endif

// forward class definitions
//
class SofParser;

// Sof: (s)ignal (o)bject (f)ile
//
// this file defines a class that is used to read and write isip objects
// to a file (binary or text). this class serves as an index, keeping
// track of all objects written to a file. note that multiple objects
// of the same class name can be written to a file.
//
class Sof {

  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------

public:

  // define the class name
  //
  static const SysString CLASS_NAME;
  
  //----------------------------------------
  //
  // Sof file parsing related constants
  //
  //----------------------------------------  

  // define magic sequences used to identify an Sof file
  //
  static const long MAX_MAGIC_LENGTH = 22;

  // define the version number and magic number
  //
  static const SysString VERSION;

  // define some sizes
  //
  static const long MESSAGE_SIZE = 1024;
  static const long CLASS_NAME_SIZE = 256;
  
  // define deletion characters
  //
  static const char DELETE_CHAR_TEXT = ' ';
  static const char DELETE_CHAR_BINARY = '\0';

  // define new line characters
  //
  static const char NEWLINE_BUFFER[];
  static const long NEWLINE_LENGTH;
  
  //----------------------------------------
  //
  // byte-mode related constants
  //
  //----------------------------------------  

  // define descriptor string related to these byte modes
  //
  static const SysString BSTR_NATIVE;
  static const SysString BSTR_SWAP;

  // define the numbers that these string should convert to
  //
  static const long BCODE_NATIVE = 1633837924;
  static const long BCODE_SWAP = 1684234849;
  
  // define the length of the byte-string for testing
  //
  static const long BSTR_LEN = 4;
  
  // determine if the machine supports IEEE floating point
  //
  static const float IEEE_FLOAT_NATIVE = 16777999408082104352768.000000;
  static const float IEEE_FLOAT_SWAP = 261007875622861537280.000000;

  //----------------------------------------
  //
  // tag related constants
  //
  //----------------------------------------  
  
  // define constants for the implicit tag number regions
  //
  // if you go over 1.07 billion implicitly numbered tags, it will error
  //
  static const long NO_TAG = SofList::NO_TAG;
  static const long ALL_TAGS = NO_TAG + 1;
  static const long FREE_TAG = NO_TAG + 2;
  static const long IMPLICIT_END = -1073741824;
  static const long IMPLICIT_START = (NO_TAG + 3);
    
  //----------------------------------------
  //
  // binary index i/o related constants
  //
  //----------------------------------------  
  
  // define the buffer size to be used. the sof binary index, when
  // written, is aligned at this buffer size to expedite i/o.
  //
  static const long BUFFER_SIZE = File::BUF_SIZE;
  
  // positions in the sequentially output symbol table
  //
  static const long SYMBOL_BASE	= (2 * sizeof(uint32) + sizeof(ubyte));
  static const long SYMBOL_OFFSET_NEXT = 0;
  static const long SYMBOL_OFFSET_IND =	SYMBOL_OFFSET_NEXT + sizeof(ubyte);
  static const long SYMBOL_OFFSET_REFS = SYMBOL_OFFSET_IND + sizeof(int32);
  static const long SYMBOL_OFFSET_NAME = SYMBOL_OFFSET_REFS + sizeof(int32);
  
  // positions in the sequentially output binary index
  //
  static const long INDEX_SIZE = (4 * sizeof(int32) + sizeof(byte8));
  static const long INDEX_OFFSET_NEXT = 0;
  static const long INDEX_OFFSET_POS = INDEX_OFFSET_NEXT + sizeof(byte8);
  static const long INDEX_OFFSET_TAG = INDEX_OFFSET_POS + sizeof(int32);
  static const long INDEX_OFFSET_SIZE = INDEX_OFFSET_TAG + sizeof(int32);
  static const long INDEX_OFFSET_NAME = INDEX_OFFSET_SIZE + sizeof(int32);

  // constant for the skip table size (partial i/o)
  //
  static const long SKIP_TABLE_GROUP = 10;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // define the default value(s) of the class data
  //
  static const unichar DEF_DELIMITER = L'@';
  static const long DEF_POS = -1;
  static const long DEF_IMPLICIT = IMPLICIT_START;
  static const boolean DEF_DISABLE_LOCK = true;
  
  // default arguments to methods
  //
  static const long ANY_SIZE = -1;
  
  //---------------------------------------
  //
  // error codes
  //
  //---------------------------------------
  
  static const long ERR				= 10000;
  static const long ERR_NOTSOF			= 10001;
  static const long ERR_NOOBJ			= 10002;
  static const long ERR_NOTAG			= 10003;
  static const long ERR_UPDATEH			= 10011;
  static const long ERR_UPDATE			= 10012;
  static const long ERR_CLOSE			= 10015;
  static const long ERR_RANGE			= 10020;
  static const long ERR_CURPOS			= 10021;
  static const long ERR_FLOAT			= 10042;
  static const long ERR_READHD			= 10043;
  static const long ERR_TYPE			= 10044;
  static const long ERR_STRUCT			= 10045;
  static const long ERR_LABEL			= 10051;
  static const long ERR_IMPLIC			= 10061;
  static const long ERR_TAG			= 10062;
  static const long ERR_BINARY			= 10063;
  static const long ERR_PARTIAL			= 10070;
  static const long ERR_RESIZE			= 10071;

  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // general information about a file
  //
  SysString name_d;                         // current filename
  SysString expanded_name_d;                // expanded filename
  File::TYPE file_type_d;	            // type of file (text or binary)  

  // I/O related variables
  //
  File fp_d;				    // active file pointer
  
  // auxiliary information
  //
  unichar delimiter_d;                     // object tag delimiter
  long end_of_header_d;                    // end of header, start of data
  long end_of_data_d;                      // end of data, start of index 
  long cur_data_d;                         // start of current object data

  // current file position (global, what ftell() would return)
  //
  long cur_pos_d;
  
  // next free implicit tag number
  //
  long implicit_count_d;		
  
  // file locking
  //
  boolean disable_lock_d;
  long lock_retry_d;
  long lock_delay_d;
  
  // symbol table used for names
  //
  SofSymbolTable table_d;
  
  // list used to process the object index
  //
  SofList index_d;

  // scratch space for magic number manipulations
  //
  SysString cname_d;                              // sof file tag 
  SysString version_d;                            // sof version
  SysString magic_d;			          // sof magic number

  // variables used in partial read and write
  //
  boolean partial_write_d;
  boolean partial_read_d;
  SofParser* vec_parser_d;
  int32* skip_table_d;
  long skip_table_incr_d;
  long last_skip_table_pos_d;
  long vec_start_pos_d;
  long vec_size_d;
  long vec_curr_elem_d;

  // the checksum read from the file
  //
  ushort file_checksum_d;
  
  // static checksum object for binary files
  //
  static Checksum cksm_d;
  
  // debugging parameters
  //
  Integral::DEBUG debug_level_d;

  // static memory manager
  //
  static MemoryManager mgr_d;

  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:

  // method: name
  //
  static const SysString& name() {
    return CLASS_NAME;
  }

  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);

  // method: setDebug
  //
  boolean setDebug(Integral::DEBUG level) {
    debug_level_d = level;
    return true;
  }
  
  // other debug methods
  //
  boolean debug(const unichar* msg) const;

  // destructor/constructor(s)
  //
  ~Sof();
  Sof();
  
  // assign methods
  //
  boolean assign(const Sof& arg);
  
  // method: operator=
  //
  Sof& operator=(const Sof& arg) {
    if (!assign(arg)) {
      Error::handle(name(), L"operator=", Error::ARG, __FILE__, __LINE__);
    }      
    return *this;
  }
  
  // i/o methods:
  //  these methods are omitted because Sof can not write itself to an
  //  sof file
  //
  
  // equality methods:
  //  these methods are omitted because they are not useful for Sof objects
  //

  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }
  
  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }
  
  // clear method
  //  this clear method is slightly different from the required clear
  //  method in that it can be used only for writable Sof files. it deletes
  //  all items from the sof file for all CMODE's.
  // 
  boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  extensions to the required public methods
  //
  //---------------------------------------------------------------------------

  // memory size methods
  //
  long memSize();
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  file operation methods
  //
  //---------------------------------------------------------------------------
    
  // method: open
  //
  boolean open(const unichar* filename, File::MODE mode = File::READ_ONLY,
	       File::TYPE type = File::DEF_TYPE) {
    SysString temp(filename);
    return open(temp, mode, type);
  }

  boolean open(const SysString& filename, File::MODE mode = File::READ_ONLY,
	       File::TYPE type = File::DEF_TYPE);

  // close methods
  //
  boolean close();
  
  // close all open Sof files (part of Error's clean exit)
  //
  static boolean closeAll();
  
  // method: setLockDisable
  //
  boolean setLockDisable(boolean disable) {
    disable_lock_d = disable;
    return true;
  }

  // method: setLockRetry
  //
  boolean setLockRetry(long retry, long delay = File::DEF_LOCK_DELAY) {
    lock_retry_d = retry;
    lock_delay_d = delay;
    return true;
  }
      
  // method: setDelimiter
  //
  boolean setDelimiter(unichar chr) {
    delimiter_d = chr;
    return true;
  }
  
  // method: getDelimiter
  //
  unichar getDelimiter() const {
    return delimiter_d;
  }
  
  // method: getName
  //
  const SysString& getName() const {
    if (!isOpen()) {
      Error::handle(name(), L"getName", Error::READ_CLOSED, __FILE__,
		    __LINE__);
    }
    return name_d;
  }

  // method: getExpandedName
  //
  const SysString& getExpandedName() const {
    if (!isOpen()) {
      Error::handle(name(), L"getName", Error::READ_CLOSED, __FILE__,
		    __LINE__);
    }
    return expanded_name_d;
  }

  // file queries methods
  //
  boolean isSof();
  static boolean isSof(const SysString& filename);
  
  // method: isText
  //
  boolean isText() const{
    return (file_type_d == File::TEXT);
  }
  
  // method: isBinary
  //
  boolean isBinary() const {
    return (file_type_d != File::TEXT);
  }
  
  // method: isOpen
  //
  boolean isOpen() const {
    return fp_d.isOpen();
  }

  // method: isSameFile
  //
  boolean isSameFile(Sof& sof_obj) {
    return (expanded_name_d.eq(sof_obj.expanded_name_d));
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  object operation methods
  //
  //---------------------------------------------------------------------------
  
  // method: find
  //
  boolean find(const SysString& name, long tag) {
    return find(table_d.getIndex(name), tag);
  }
  long first(const SysString& name);
  long last(const SysString& name);

  // method: next
  //  this method finds the next instance of this object in the index
  //
  long next(const SysString& name, long cur_tag) {
    long name_ind = table_d.getIndex(name);    // find in symbol table
    return index_d.next(name_ind, cur_tag);    // return the tag
  }
  
  // method: prev
  //
  long prev(const SysString& name, long cur_tag) {
    long name_ind = table_d.getIndex(name);
    return index_d.prev(name_ind, cur_tag);
  }
  
  // object put methods
  //
  boolean put(const SysString& name, long size);
  boolean put(const SysString& name, long tag, long size);

  // object remove methods
  //
  boolean remove(const SysString& name, long object_tag);
  boolean remove(long name, long object_tag);
  boolean remove(const SysString& name);
  boolean remove(long name);
  
  // object copy methods
  //
  boolean copy(long o_tag, Sof& i_sof, const SysString& i_cname, long i_tag);
  boolean copy(long o_tag, Sof& i_sof, long i_cname, long i_tag);
  boolean copy(Sof& i_sof, const SysString& i_cname);
  boolean copy(Sof& i_sof, long i_cname);

  // object operations: get methods
  //
  long getObjectSize(const SysString& name, long tag);
  long getObjectSize();

  // index count methods
  //
  
  // method: getCount
  //  this method gets the number of objects with this class name
  //
  long getCount(const SysString& name) {
    return index_d.getCount(table_d.getIndex(name));
  }

  // method: getCount
  //
  long getCount() {
    return index_d.getCount();    
  }

  // method: getNameCount
  //  this method gets the number of classes in the file,
  //  note it only works because the index is sorted
  //
  long getNameCount() {
    return table_d.getCount();
  }

  // method: enumerate
  //  this method enumerates all objects in an sof file
  //
  boolean enumerate(SofList& index, SofSymbolTable& table) const {
     index.assign(index_d);
     table.assign(table_d);
     return true;
  }

  // positioning methods (relative to current object)
  //
  boolean seek(long offset, File::SEEK whence);
  long tell() const;

  // method: rewind
  //
  boolean rewind() {
    if (cur_data_d < 0) {
      return Error::handle(name(), L"rewind", SofList::ERR, __FILE__,
			   __LINE__);
    }
    return fseek(cur_data_d, File::POS);
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  input and output methods
  //
  //---------------------------------------------------------------------------
  
  // wrap the base i/o functions with automatic byte-swapping and
  // range checking. imagine each object within an Sof file is it's
  // own file, so rewind brings you to the beginning of that object's
  // space, not the begining of the actual file.
  //

  // binary i/o methods
  //
  long read(void* ptr, long size, long nitems);
  long write(const void* ptr, long size, long nitems);

  // text i/o methods
  //
  boolean gets(SysString& ptr, long size = BUFFER_SIZE);
  boolean puts(const SysString& ptr);

  // write label methods
  //
  boolean writeLabelPrefix(const SysString& param_name);
  boolean writeLabelSuffix(const SysString& param_name);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  formatting methods
  //
  //---------------------------------------------------------------------------
  
  // these methods are for text sof file only. refer File class for
  // the meaning of these methods
  //
  
  // method: increaseIndention
  //
  boolean increaseIndention() {
    if (isText()) {
      return fp_d.increaseIndention();
    }
    return false;
  }

  // method: decreaseIndention
  //
  boolean decreaseIndention() {
    if (isText()) {
      return fp_d.decreaseIndention();
    }
    return false;
  }
  
  // method: setLineWrap
  //
  boolean setLineWrap(long ncols) {
    if (isText()) {
      return fp_d.setLineWrap(ncols);
    }
    return false;
  }

  // method: getLineLength
  //
  long getLineLength() const {
    if (isText()) {
      return fp_d.getLineLength();            // only for text files
    }
    return -1;                                // exit ungracefully 
  }

  // method: getLineWrap
  //
  long getLineWrap() const {
    if (isText()) {
      return fp_d.getLineWrap();
    }
    return -1;
  }
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  methods that facilitate partial i/o
  //
  //---------------------------------------------------------------------------

  // partial write configuration methods
  //
  
  // methods to facilitate partial i/o
  //
  boolean startPartialWrite();
  boolean stopPartialWrite();
  boolean startPartialRead();
  boolean stopPartialRead();

  // method: getSkipTable
  //
  int32* getSkipTable() {
    if ((!partial_write_d) && (!partial_read_d)) {
      Error::handle(name(), L"getSkipTable", ERR, __FILE__, __LINE__);
    }
    return skip_table_d;
  }

  // method: getSkipTable
  //
  const int32* getSkipTable() const {
    if ((!partial_write_d) && (!partial_read_d)) {
      Error::handle(name(), L"getSkipTable", ERR, __FILE__, __LINE__);
    }
    return skip_table_d;
  }

  // method: getSkipTableIncr
  //
  long getSkipTableIncr() const {
    if ((!partial_write_d) && (!partial_read_d)) {
      return Error::handle(name(), L"getSkipTableIncr", ERR,
			   __FILE__, __LINE__);
    }
    return skip_table_incr_d;
  }

  // method: getLastSkipTablePos
  //
  long getLastSkipTablePos() const {
    if ((!partial_write_d) && (!partial_read_d)) {
      return Error::handle(name(), L"getLastSkipTablePos", ERR,
			   __FILE__, __LINE__);
    }
    return last_skip_table_pos_d;
  }

  // method: getStartPos
  //
  long getStartPos() const {
    if ((!partial_write_d) && (!partial_read_d)) {
      return Error::handle(name(), L"getStartPos", ERR,
			   __FILE__, __LINE__);
    }
    return vec_start_pos_d;
  }

  // method: getVecSize
  //
  long getVecSize() const {
    if ((!partial_write_d) && (!partial_read_d)) {
      return Error::handle(name(), L"getVecSize", ERR,
			   __FILE__, __LINE__);
    }
    return vec_size_d;
  }
  
  // method: getVecCurrentElement
  //
  long getVecCurrentElement() const {
    if ((!partial_write_d) && (!partial_read_d)) {
      return Error::handle(name(), L"getVecCurrentElement", ERR,
			   __FILE__, __LINE__);
    }
    return vec_curr_elem_d;
  }

  // method: getVecParser
  //
  const SofParser& getVecParser() const;
  SofParser& getVecParser();
  
  // method: setSkipTableIncr
  //
  boolean setSkipTableIncr(long pos) {
    if ((!partial_write_d) && (!partial_read_d)) {
      return Error::handle(name(), L"getSkipTableIncr", ERR,
			   __FILE__, __LINE__);
    }
    skip_table_incr_d = pos;
    return true;
  }

  // method: setLastSkipTablePos
  //
  boolean setLastSkipTablePos(long pos) {
    if ((!partial_write_d) && (!partial_read_d)) {
      return Error::handle(name(), L"getLastSkipTablePos", ERR,
			   __FILE__, __LINE__);
    }
    last_skip_table_pos_d = pos;
    return true;
  }

  // method: setStartPos
  //
  boolean setStartPos(long pos) {
    if ((!partial_write_d) && (!partial_read_d)) {
      return Error::handle(name(), L"setStartPos", ERR,
			   __FILE__, __LINE__);
    }
    vec_start_pos_d = pos;
    return true;
  }
  

  // method: setVecSize
  //
  boolean setVecSize(long pos) {
    if ((!partial_write_d) && (!partial_read_d)) {
      return Error::handle(name(), L"setVecSize", ERR,
			   __FILE__, __LINE__);
    }
    vec_size_d = pos;
    return true;
  }
  
  // method: setVecCurrentElement
  //
  boolean setVecCurrentElement(long pos) {
    if ((!partial_write_d) && (!partial_read_d)) {
      return Error::handle(name(), L"setVecCurrentElement", ERR,
			   __FILE__, __LINE__);
    }
    vec_curr_elem_d = pos;
    return true;
  }

  // method: getPartialWrite
  //
  boolean getPartialWrite() const {
    return partial_write_d;
  }

  // method: getPartialRead
  //
  boolean getPartialRead() const {
    return partial_read_d;
  }

  // method: clearSkipTable
  //
  boolean clearSkipTable() {
    if (skip_table_d == (int32*)NULL) {
      return Error::handle(name(), L"clearSkipTable", Error::MEM,
			   __FILE__, __LINE__);
    }
    for (long i = 0; i < SKIP_TABLE_GROUP; i++) {
      skip_table_d[i] = -1;
    }
    return true;
  }

  // method: writeSkipTable
  //
  boolean writeSkipTable() {
    if (skip_table_d == (int32*)NULL) {
      return Error::handle(name(), L"writeSkipTable", Error::MEM,
			   __FILE__, __LINE__);
    }
    long n = write(skip_table_d, sizeof(int32), SKIP_TABLE_GROUP);
    return (n == SKIP_TABLE_GROUP);
  }

  // method: readSkipTable
  //
  boolean readSkipTable() {
    if (skip_table_d == (int32*)NULL) {
      return Error::handle(name(), L"writeSkipTable", Error::MEM,
			   __FILE__, __LINE__);
    }
    last_skip_table_pos_d = tell();
    long n = read(skip_table_d, sizeof(int32), SKIP_TABLE_GROUP);
    return (n == SKIP_TABLE_GROUP);
  }

  // resize entry methods (should only be called in partial write mode)
  //
  boolean resize(long size);

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // method: copy constructor
  //  the method is private so we can't copy Sof objects.
  //
  Sof(const Sof& arg) {
    Error::handle(name(), L"Sof Constructor",
		  Error::BAD_CSTR, __FILE__, __LINE__);
  }
  
  // free memory methods
  //
  boolean cleanUp();
  boolean freeIndex();

  // update methods:
  //  update index and header
  //
  boolean update();	

  // binary index i/o methods
  //
  boolean readIndex();			
  boolean writeIndex();			

  // symbol table i/o methods
  //
  boolean readTable();	
  boolean writeTable();			
  
  // open read methods:
  //  these methods open an sof file for read access
  //
  boolean openRead();
  
  // method: openReadText
  //
  boolean openReadText() {
    return openReadIndexText();
  }
  
  // method: openReadBinary
  //
  boolean openReadBinary() {
    return openReadIndexBinary();
  }

  // open read index methods:
  //  these methods open a sof file for reading the indices
  //
  boolean openReadIndexText();
  boolean openReadIndexBinary();
  
  // open write methods:
  //  these methods open an sof file for write access
  //
  boolean openWrite(File::MODE access_mode);

  // text file label handling methods
  //
  boolean writeLabel(long name, long tag);
  boolean writeLabel(const SysString& name, long tag);
  boolean parseLabel(SysString& name, long& tag, const SysString& buf);
  boolean skipLabel(); 
 
  // method: seekData
  //  these methods seek to the data of an object
  //
  boolean seekData() {
    if (file_type_d == File::TEXT) {
      return seekDataText();
    }
    return seekDataBinary();
  }
  
  boolean seekDataText();
  boolean seekDataBinary();
  
  // internal object manipulation methods:
  //  the public interface is far simpler
  //
  boolean find(long name, long tag);
  boolean add(const SysString& name, long size, long tag = FREE_TAG);
  boolean add(long name, long size, long tag = FREE_TAG);
  
  // resize methods:
  //  resize the current entry, preserving current data
  //
  boolean resize(const SysString& name, long tag, long size);
  
  // binary i/o methods:
  //  read/write with byte swapping without range checking
  //
  long fwrite(const void* ptr, long size, long nitems);
  long fread(void* ptr, long size, long nitems);
  
  // position methods
  //
  boolean fseek(long offset, File::SEEK whence);
  long ftell() const;

  // copy segment methods:
  //  efficient methods for clearing out a section of a file and
  //  copying a section of a file from one place to another.
  //
  boolean clearSpace(long nbytes);
  boolean copySegment(long src_pos, long size);
  boolean copySegment(long src_pos, long dest_pos, long size);
  
  // error pointer setting methods
  //
  boolean setErrorPointer();

  // register pointer maintaining methods:
  //  maintain an array of all open Sof pointers (part of clean exit)
  //
  boolean registerPtr();
  boolean unRegisterPtr();

  //---------------------------------------------------------------------------
  //
  // friend functions and classes:
  //  while friend functions and classes are generally discouraged in the ISIP
  //  environment, they are used in the Sof class to allow the
  //  AudioFile class direct access to Sof's internals for efficiency.
  //
  //---------------------------------------------------------------------------

  // class: AudioFile
  //
  friend class AudioFile;
};

// end of include file
//
#endif
