Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

BufferedSink.cpp

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002 
00003    Copyright (c) 2000 Tyrell Corporation. All rights reserved.
00004 
00005    Tyrell DarkIce
00006 
00007    File     : BufferedSink.cpp
00008    Version  : $Revision: 1.6 $
00009    Author   : $Author: darkeye $
00010    Location : $Source: /cvsroot/darkice/darkice/src/BufferedSink.cpp,v $
00011    
00012      the buffer is filled like this:
00013      
00014      buffer                                         bufferEnd
00015       |                                                    |
00016       +----------+--------------------------+--------------+
00017                  |<---- valid data -------->|
00018                 outp                       inp 
00019 
00020      buffer                                         bufferEnd
00021       |                                                    |
00022       +----------------+--------------+--------------------+
00023       -- valid data -->|              |--- valid data ----->
00024                       inp            outp
00025 
00026 
00027 
00028    Copyright notice:
00029 
00030     This program is free software; you can redistribute it and/or
00031     modify it under the terms of the GNU General Public License  
00032     as published by the Free Software Foundation; either version 2
00033     of the License, or (at your option) any later version.
00034    
00035     This program is distributed in the hope that it will be useful,
00036     but WITHOUT ANY WARRANTY; without even the implied warranty of 
00037     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
00038     GNU General Public License for more details.
00039    
00040     You should have received a copy of the GNU General Public License
00041     along with this program; if not, write to the Free Software
00042     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00043 
00044 ------------------------------------------------------------------------------*/
00045 
00046 /* ============================================================ include files */
00047 
00048 #ifdef HAVE_CONFIG_H
00049 #include "config.h"
00050 #endif
00051 
00052 #ifdef HAVE_STRING_H
00053 #include <string.h>
00054 #else
00055 #error need string.h
00056 #endif
00057 
00058 
00059 #include "Exception.h"
00060 #include "BufferedSink.h"
00061 
00062 
00063 /* ===================================================  local data structures */
00064 
00065 
00066 /* ================================================  local constants & macros */
00067 
00068 /*------------------------------------------------------------------------------
00069  *  File identity
00070  *----------------------------------------------------------------------------*/
00071 static const char fileid[] = "$Id: BufferedSink.cpp,v 1.6 2002/10/19 12:21:28 darkeye Exp $";
00072 
00073 
00074 /* ===============================================  local function prototypes */
00075 
00076 
00077 /* =============================================================  module code */
00078 
00079 /*------------------------------------------------------------------------------
00080  *  Initialize the object
00081  *----------------------------------------------------------------------------*/
00082 void
00083 BufferedSink :: init (  Sink          * sink,
00084                         unsigned int    size,
00085                         unsigned int    chunkSize )     throw ( Exception )
00086 {
00087     if ( !sink ) {
00088         throw Exception( __FILE__, __LINE__, "no sink");
00089     }
00090 
00091     this->sink         = sink;                    // create a reference
00092     this->chunkSize    = chunkSize ? chunkSize : 1;
00093     this->bufferSize   = size;
00094     // make bufferSize a multiple of chunkSize
00095     this->bufferSize  -= this->bufferSize % this->chunkSize;
00096     this->peak         = 0;
00097     this->misalignment = 0;
00098     this->buffer       = new unsigned char[bufferSize];
00099     this->bufferEnd    = buffer + bufferSize;
00100     this->inp          = buffer;
00101     this->outp         = buffer;
00102 }
00103 
00104 
00105 /*------------------------------------------------------------------------------
00106  *  Copy Constructor
00107  *----------------------------------------------------------------------------*/
00108 BufferedSink :: BufferedSink (  const BufferedSink &  buffer )
00109                                                         throw ( Exception )
00110 {
00111     init( buffer.sink.get(), buffer.bufferSize, buffer.chunkSize);
00112 
00113     this->peak         = buffer.peak;
00114     this->misalignment = buffer.misalignment;
00115     memcpy( this->buffer, buffer.buffer, this->bufferSize);
00116 }
00117 
00118 
00119 /*------------------------------------------------------------------------------
00120  *  De-initalize the object
00121  *----------------------------------------------------------------------------*/
00122 void
00123 BufferedSink :: strip ( void )                      throw ( Exception )
00124 {
00125     if ( isOpen() ) {
00126         close();
00127     }
00128 
00129     sink = 0;                                   // delete the reference
00130     delete buffer;
00131 }
00132 
00133 
00134 /*------------------------------------------------------------------------------
00135  *  Assignment operator
00136  *----------------------------------------------------------------------------*/
00137 BufferedSink &
00138 BufferedSink :: operator= (     const BufferedSink &  buffer )
00139                                                     throw ( Exception )
00140 {
00141     if ( this != &buffer ) {
00142         strip();
00143         Sink::operator=( buffer );
00144         init( buffer.sink.get(), buffer.bufferSize, buffer.chunkSize);
00145         
00146         this->peak         = buffer.peak;
00147         this->misalignment = buffer.misalignment;
00148         memcpy( this->buffer, buffer.buffer, this->bufferSize);
00149     }
00150 
00151     return *this;
00152 }
00153 
00154 
00155 /*------------------------------------------------------------------------------
00156  *  Store bufferSize bytes into the buffer
00157  *  All data is consumed. The return value is less then bufferSize only
00158  *  if the BufferedSink's internal buffer is smaller than bufferSize,
00159  *  thus can't hold that much
00160  *  The data to be stored is treated as parts with chunkSize size
00161  *  Only full chunkSize sized parts are stored
00162  *----------------------------------------------------------------------------*/
00163 unsigned int
00164 BufferedSink :: store (     const void    * buffer,
00165                             unsigned int    bufferSize )    throw ( Exception )
00166 {
00167     const unsigned char   * buf;
00168     unsigned int            size;
00169     unsigned int            i;
00170     unsigned char         * oldInp;
00171 
00172     if ( !buffer ) {
00173         throw Exception( __FILE__, __LINE__, "buffer is null");
00174     }
00175 
00176     if ( !bufferSize ) {
00177         return 0;
00178     }
00179 
00180     oldInp = inp;
00181     buf    = (const unsigned char *) buffer;
00182     
00183     // adjust so it is a multiple of chunkSize
00184     bufferSize -= bufferSize % chunkSize;
00185 
00186     // cut the front of the supplied buffer if it wouldn't fit
00187     if ( bufferSize > this->bufferSize ) {
00188         size  = this->bufferSize - 1;
00189         size -= size % chunkSize;       // keep it a multiple of chunkSize
00190         buf  += bufferSize - size;
00191     } else {
00192         size = bufferSize;
00193     }
00194 
00195     // copy the data into the buffer
00196     i = bufferEnd - inp;
00197     if ( (i % chunkSize) != 0 ) {
00198         throw Exception( __FILE__, __LINE__, "copy quantity not aligned", i);
00199     }
00200 
00201     if ( size <= i ) {
00202         // the place between inp and bufferEnd is
00203         // big enough to hold the data
00204         
00205         memcpy( inp, buf, size);
00206         inp = slidePointer( inp, size);
00207 
00208         // adjust outp, lose the data that was overwritten, if any
00209         if ( outp > oldInp && outp <= inp ) {
00210             outp = slidePointer( inp, chunkSize);
00211         }
00212 
00213     } else {
00214         // the place between inp and bufferEnd is not
00215         // big enough to hold the data
00216         // writing will take place in two turns, once from
00217         // inp -> bufferEnd, then from buffer ->
00218 
00219         memcpy( inp, buf, i);
00220         i = size - i;
00221         if ( (i % chunkSize) != 0 ) {
00222             throw Exception(__FILE__, __LINE__, "copy quantity not aligned", i);
00223         }
00224         memcpy( this->buffer, buf, i);
00225         inp = slidePointer( this->buffer, i);
00226         
00227         // adjust outp, lose the data that was overwritten, if any
00228         if ( outp <= oldInp ) {
00229             if ( outp < inp ) {
00230                 outp = slidePointer( inp, chunkSize);
00231             }
00232         } else {
00233             outp = slidePointer( inp, chunkSize);
00234         }
00235     }
00236 
00237     updatePeak();
00238 
00239     if ( ((inp - this->buffer) % chunkSize) != 0 ) {
00240         throw Exception( __FILE__, __LINE__,
00241                          "inp not aligned", inp - this->buffer);
00242     }
00243     if ( ((outp - this->buffer) % chunkSize) != 0 ) {
00244         throw Exception( __FILE__, __LINE__,
00245                          "outp not aligned", outp - this->buffer);
00246     }
00247 
00248     return size;
00249 }
00250 
00251 
00252 /*------------------------------------------------------------------------------
00253  *  Write some data to the sink
00254  *  if len == 0, try to flush the buffer
00255  *----------------------------------------------------------------------------*/
00256 unsigned int
00257 BufferedSink :: write (    const void    * buf,
00258                            unsigned int    len )       throw ( Exception )
00259 {
00260     unsigned int    length;
00261     unsigned int    soFar;
00262     unsigned char * b = (unsigned char *) buf;
00263 
00264     if ( !buf ) {
00265         throw Exception( __FILE__, __LINE__, "buf is null");
00266     }
00267 
00268     if ( !isOpen() ) {
00269         return 0;
00270     }
00271 
00272     if ( !align() ) {
00273         return 0;
00274     }
00275 
00276     // make it a multiple of chunkSize
00277     len -= len % chunkSize;
00278 
00279     // try to write data from the buffer first, if any
00280     if ( inp != outp ) {
00281         unsigned int    size  = 0;
00282         unsigned int    total = 0;
00283 
00284         if ( outp > inp ) {
00285             // valuable data is between outp -> bufferEnd and buffer -> inp
00286             // try to write the outp -> bufferEnd
00287             // the rest will be written in the next if
00288 
00289             size    = bufferEnd - outp - 1;
00290             size   -= size % chunkSize;
00291             soFar   = 0;
00292 
00293             while ( outp > inp && soFar < size && sink->canWrite( 0, 0) ) {
00294                 length  = sink->write( outp + soFar, size - soFar);
00295                 outp    = slidePointer( outp, length);
00296                 soFar  += length;
00297             }
00298 
00299             total += soFar;
00300         }
00301 
00302         if ( outp < inp ) {
00303             // valuable data is between outp and inp
00304             // in the previous if wrote all data from the end
00305             // this part will write the rest
00306 
00307             size    = inp - outp;
00308             soFar   = 0;
00309 
00310             while ( soFar < size && sink->canWrite( 0, 0) ) {
00311                 length  = sink->write( outp + soFar, size - soFar);
00312                 outp    = slidePointer( outp, length);
00313                 soFar  += length;
00314             }
00315 
00316             total += soFar;
00317         }
00318 
00319         while ( (outp - buffer) % chunkSize ) {
00320             slidePointer( outp, 1);
00321         }
00322 
00323         // calulate the misalignment to chunkSize boundaries
00324         misalignment = (chunkSize - (total % chunkSize)) % chunkSize;
00325     }
00326 
00327     if ( !align() ) {
00328         return 0;
00329     }
00330 
00331     // the internal buffer is empty, try to write the fresh data
00332     soFar = 0;
00333     if ( inp != outp ) {
00334         while ( soFar < len && sink->canWrite( 0, 0) ) {
00335             soFar += sink->write( b + soFar, len - soFar);
00336         }
00337     }
00338     length = soFar;
00339 
00340     // calulate the misalignment to chunkSize boundaries
00341     misalignment = (chunkSize - (length % chunkSize)) % chunkSize;
00342 
00343     if ( length < len ) {
00344         // if not all fresh could be written, store the remains
00345 
00346         store( b + length, len - length);
00347     }
00348 
00349     // tell them we ate everything up to chunkSize alignment
00350     return len;
00351 }
00352 
00353 
00354 /*------------------------------------------------------------------------------
00355  *  Close the sink, lose all pending data
00356  *----------------------------------------------------------------------------*/
00357 void
00358 BufferedSink :: close ( void )                      throw ( Exception )
00359 {
00360     if ( !isOpen() ) {
00361         return;
00362     }
00363 
00364     flush();
00365     sink->close();
00366     inp = outp = buffer;
00367 }
00368 
00369 
00370 /*------------------------------------------------------------------------------
00371  
00372   $Source: /cvsroot/darkice/darkice/src/BufferedSink.cpp,v $
00373 
00374   $Log: BufferedSink.cpp,v $
00375   Revision 1.6  2002/10/19 12:21:28  darkeye
00376   fixed comment typo
00377 
00378   Revision 1.5  2001/08/30 17:25:56  darkeye
00379   renamed configure.h to config.h
00380 
00381   Revision 1.4  2000/11/11 12:33:13  darkeye
00382   added kdoc-style documentation
00383 
00384   Revision 1.3  2000/11/10 20:16:21  darkeye
00385   first real tests with multiple streaming
00386 
00387   Revision 1.2  2000/11/05 14:08:27  darkeye
00388   changed builting to an automake / autoconf environment
00389 
00390   Revision 1.1.1.1  2000/11/05 10:05:48  darkeye
00391   initial version
00392 
00393   
00394 ------------------------------------------------------------------------------*/
00395 

Generated on Fri May 19 15:36:48 2006 for DarkIce by  doxygen 1.4.4