home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1995 November / Macworld Nov ’95.toast / Developers / Advanced i⁄o / endian_io.h < prev    next >
Encoding:
Text File  |  1995-06-19  |  6.6 KB  |  230 lines  |  [TEXT/ALFA]

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *               Class Endian_IO
  6.  *    to read integers of various sizes taking the byte order
  7.  *                into account
  8.  *              and bit-stream IO
  9.  *
  10.  *   Two different byte orders are supported
  11.  *    bigendian    - most significant byte first
  12.  *    littleendian    - most significant byte last
  13.  *
  14.  * $Id: endian_io.h,v 2.1 1995/03/02 18:06:20 oleg Exp oleg $
  15.  *
  16.  ************************************************************************
  17.  */
  18.  
  19. #ifndef __GNUC__
  20. #pragma once
  21. #endif
  22. #ifndef endian_io_h
  23. #define endian_io_h
  24.  
  25. #ifdef __GNUC__
  26. #pragma interface
  27. #endif
  28.  
  29. #include <fstream.h>
  30. #include "myenv.h"
  31.  
  32. #ifdef __GNUC__
  33. #define _IOS_Bin_               ios::bin
  34. #else
  35. #define _IOS_Bin_               ios::binary
  36. #endif
  37.  
  38.                 // Extension to 'ios' to keep byte order
  39.                 // and stream sharing info
  40. class EndianIOData : virtual public ios
  41. {
  42.   enum { MSBfirst, LSBfirst } byte_order;
  43.   bool shared;            // Was this stream shared with some other
  44.                 // stream?
  45.  
  46. public:
  47.                 // Means having this stream reference the same
  48.                 // disk structure *and* the memory buffer
  49.                 // as a_file
  50.   void share_with(EndianIOData& a_file);
  51.  
  52.   EndianIOData(void) : byte_order(LSBfirst), shared(false)  {}
  53.   ~EndianIOData(void);        // Check for sharing and break it
  54.  
  55.   void set_bigendian(void)          // Most significant byte first
  56.                   { byte_order = MSBfirst; }
  57.   void set_littlendian(void)        // Least significant byte first
  58.                 { byte_order = LSBfirst; }
  59.   bool q_MSBfirst(void) const    { return byte_order == MSBfirst; }
  60.   bool was_shared(void) const    { return shared; }
  61.                 // Returns TRUE if something goes wrong
  62.                 // with the I/O
  63.   bool operator ! ()    { return !good(); }
  64.   void error(const char *descr);
  65.                 // Make sure the stream was opened successfully
  66.   void assert_open(const char * file_name);
  67. };
  68.  
  69.             // Class to read (binary) data from the input stream
  70.             // keeping in mind the byte order
  71. class EndianIn : public EndianIOData, public ifstream
  72. {
  73. public:
  74.   EndianIn(void) {}
  75.   EndianIn(const char * file_name) : ifstream(file_name,ios::in|_IOS_Bin_)
  76.                 { assert_open(file_name); }
  77.                         // Hint: which destr do first
  78.   ~EndianIn(void) { this->EndianIOData::~EndianIOData(); }
  79.  
  80.                     // Open by example. File handle of
  81.                     // 'file' is dup-ed, so closing the
  82.                     // present file would not close 'file'
  83.   EndianIn(EndianIn& file)        { share_with(file); }
  84.  
  85.   void open(const char *name, int mode=ios::in|_IOS_Bin_)
  86.         { ifstream::open(name,mode); assert_open(name); }
  87.  
  88.   void close(void);        // Close the stream breaking sharing if any
  89.  
  90.                 // The following I/O functions take
  91.                 // the char string op_description
  92.                 // that tells what this operation is for
  93.                 // On error, this string is printed along
  94.                 // with the error description
  95.   unsigned char  read_byte(const char * op_description);
  96.   unsigned short read_short(const char * op_description);
  97.   unsigned long  read_long(const char * op_description);
  98. };
  99.  
  100. inline unsigned char EndianIn::read_byte(const char * op_description) 
  101. {
  102.   unsigned char c;
  103.   if( !get(c) )
  104.     error(op_description);
  105.   return c;
  106. }
  107.  
  108.             // Class to write (binary) data from the input stream
  109.             // keeping in mind the byte order
  110. class EndianOut : public EndianIOData, public ofstream
  111. {
  112. public:
  113.   EndianOut(void) {}
  114.   EndianOut(const char * file_name)
  115.     : ofstream(file_name,ios::out|ios::trunc|_IOS_Bin_)
  116.                 { assert_open(file_name); }
  117.                         // Hint: which destr do first
  118.   ~EndianOut(void) { this->EndianIOData::~EndianIOData(); }
  119.  
  120.                     // Open by example. File handle of
  121.                     // 'file' is dup-ed, so closing the
  122.                     // present file would not close 'file'
  123.   EndianOut(EndianOut& file)        { share_with(file); }
  124.  
  125.   void open(const char *name, int mode=ios::out|ios::trunc|_IOS_Bin_, int prot=0644)
  126.         { ofstream::open(name,mode); assert_open(name); }
  127.  
  128.   void close(void);        // Close the stream
  129.  
  130.                 // The following I/O functions take
  131.                 // the char string op_description
  132.                 // that tells what this operation is for
  133.                 // On error, this string is printed along
  134.                 // with the error description
  135.  
  136.                 // Note, the first operand of write_byte
  137.                 // has to be specified as 'int' rather
  138.                 // than 'unsigned char', as bizarre as
  139.                 // it may seem. Otherwise, write_byte(0xff)
  140.                 // results in the i/o error
  141.                 // 'Inappropriate IOCTL for device'
  142.                 // after some 2000-4000 writings such a byte.
  143.   void write_byte(const int item, const char * op_description = "");
  144.   void write_short(const unsigned short item, const char* op_description = "");
  145.   void write_long(const unsigned long item, const char * op_description = "");
  146. };
  147.  
  148. /*
  149.  *------------------------------------------------------------------------
  150.  *            Bit-stream Input-Output
  151.  * Note, bits are written in first-in first-out mode
  152.  */
  153.  
  154. class BitIOBuffer
  155. {
  156. protected:
  157.   unsigned char buffer;
  158.   enum { largest_bit_in_buffer = (1<<7) };
  159.   unsigned char curr_bit_pos;
  160. public:
  161.   BitIOBuffer(void) : buffer(0), curr_bit_pos(largest_bit_in_buffer) {}
  162. };
  163.  
  164. class BitIn : BitIOBuffer, public EndianIn
  165. {
  166. public:
  167.             // This is a dummy constructor. Use open() function
  168.             // of EndianIO class to perform the actual opening
  169.   BitIn(void) {}
  170.  
  171.   int  get_bit(void);            // Get a bit from the input stream
  172.   short get_short(void);        // Get a short integer that was written
  173.                       // using a variable size code
  174. };
  175.  
  176. class BitOut : BitIOBuffer, public EndianOut
  177. {
  178. public:
  179.             // This is a dummy constructor. Use open() function
  180.             // of EndianIO class to perform the actual opening
  181.   BitOut(void) {}
  182.   ~BitOut(void);
  183.  
  184.   void put_bit(const char bit);        // Write a bit into the output stream
  185.   void put_short(const short item);    // Write a signed short integer 
  186.                       // using a variable size code
  187.   void close(void);            // Close the stream
  188. };
  189.  
  190.             // Put a bit (0/1) into the bit stream
  191. inline void BitOut::put_bit(const char bit)
  192. {
  193.   if( bit )
  194.     buffer |= curr_bit_pos;
  195.   if( (curr_bit_pos>>=1) == 0 )
  196.     write_byte(buffer), curr_bit_pos = largest_bit_in_buffer, buffer = 0;
  197. }
  198.  
  199.             // Flush the bit buffer on closing the stream      
  200. inline void BitOut::close(void)
  201. {
  202.                     // If the buffer contains something
  203.   if( curr_bit_pos != largest_bit_in_buffer )
  204.   {
  205.     write_byte(buffer);            // Flush the buffer
  206.     curr_bit_pos = largest_bit_in_buffer, buffer = 0;
  207.   }
  208.   EndianOut::close();
  209. }
  210.  
  211. inline BitOut::~BitOut(void)                { close(); }
  212.  
  213.  
  214.             // Read a bit from the bit stream
  215. inline int BitIn::get_bit(void)
  216. {
  217.   if( curr_bit_pos & largest_bit_in_buffer )
  218.   {
  219.     if( eof() ) 
  220.       error("Reading an 8-bit chunk");
  221.     get(buffer);
  222.   }
  223.   unsigned char bit_pos = curr_bit_pos;
  224.   if( (curr_bit_pos >>=1) == 0 )
  225.     curr_bit_pos = largest_bit_in_buffer;
  226.   return buffer & bit_pos ? 1 : 0;
  227. }
  228.  
  229. #endif
  230.