dcrledec.h

00001 /*
00002  *
00003  *  Copyright (C) 1994-2005, OFFIS
00004  *
00005  *  This software and supporting documentation were developed by
00006  *
00007  *    Kuratorium OFFIS e.V.
00008  *    Healthcare Information and Communication Systems
00009  *    Escherweg 2
00010  *    D-26121 Oldenburg, Germany
00011  *
00012  *  THIS SOFTWARE IS MADE AVAILABLE,  AS IS,  AND OFFIS MAKES NO  WARRANTY
00013  *  REGARDING  THE  SOFTWARE,  ITS  PERFORMANCE,  ITS  MERCHANTABILITY  OR
00014  *  FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES  OR
00015  *  ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
00016  *  PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
00017  *
00018  *  Module:  dcmdata
00019  *
00020  *  Author:  Marco Eichelberg
00021  *
00022  *  Purpose: RLE decompressor
00023  *
00024  *  Last Update:      $Author: meichel $
00025  *  Update Date:      $Date: 2005/12/08 16:28:36 $
00026  *  Source File:      $Source: /share/dicom/cvs-depot/dcmtk/dcmdata/include/dcmtk/dcmdata/dcrledec.h,v $
00027  *  CVS/RCS Revision: $Revision: 1.4 $
00028  *  Status:           $State: Exp $
00029  *
00030  *  CVS/RCS Log at end of file
00031  *
00032  */
00033 
00034 #ifndef DCRLEDEC_H
00035 #define DCRLEDEC_H
00036 
00037 #include "dcmtk/config/osconfig.h"
00038 #include "dcmtk/dcmdata/dcerror.h"
00039 
00043 class DcmRLEDecoder
00044 {
00045 public:
00046 
00051   DcmRLEDecoder(size_t outputBufferSize)
00052   : fail_(0)
00053   , outputBufferSize_(outputBufferSize)
00054   , outputBuffer_(NULL)
00055   , offset_(0)
00056   , suspendInfo_(128)
00057   {
00058     if (outputBufferSize_ == 0) fail_ = 1;
00059     else
00060     {
00061       outputBuffer_ = new unsigned char[outputBufferSize_];
00062       if (outputBuffer_ == NULL) fail_ = 1;
00063     }
00064   }
00065 
00067   ~DcmRLEDecoder()
00068   {
00069     delete[] outputBuffer_;
00070   }
00071 
00075   inline void clear()
00076   {
00077     offset_ = 0;
00078     suspendInfo_ = 128;
00079     if (outputBuffer_) fail_ = 0;
00080   }
00081 
00082 
00083   inline OFCondition decompress(void *compressedData, size_t compressedSize)
00084   {
00085     // we allow a call for zero bytes
00086     if (compressedSize == 0) return EC_Normal;
00087 
00088     OFCondition result = EC_IllegalCall;
00089 
00090     // check parameters passed by caller
00091     if (compressedData == NULL) fail_ = 1;
00092 
00093     if (! fail_)  // if fail_ is true, just ignore input
00094     {
00095       result = EC_Normal;
00096       unsigned char ch;
00097       unsigned char nbytes;
00098       unsigned char *cp = OFstatic_cast(unsigned char *, compressedData);
00099 
00100       // check if we suspended last time, clean up
00101       if (suspendInfo_ > 128)
00102       {
00103         // DICOM packbit scheme uses 257 - nbytes to represent replicate runs
00104         nbytes = OFstatic_cast(unsigned char, 257 - suspendInfo_);
00105 
00106         // suspended replicate run. compressedSize cannot be zero now.
00107         suspendInfo_ = 128;
00108 
00109         ch = *cp++;
00110         --compressedSize;
00111         replicate(ch, nbytes);
00112       }
00113       else if (suspendInfo_ < 128)
00114       {
00115         // suspended literal run
00116         nbytes = OFstatic_cast(unsigned char, (suspendInfo_ & 0x7f) + 1);
00117         suspendInfo_ = 128;
00118         if (compressedSize < nbytes)
00119         {
00120           // we're going to suspend again (oops?), prepare everything
00121           suspendInfo_ = OFstatic_cast(unsigned char, nbytes - compressedSize - 1);
00122           nbytes = OFstatic_cast(unsigned char, compressedSize);
00123           result = EC_StreamNotifyClient;
00124         }
00125 
00126         literal(cp, nbytes);
00127         compressedSize -= nbytes;
00128         cp += nbytes;
00129       }
00130 
00131       // continue with ordinary RLE decompression
00132       while (compressedSize && (! fail_))
00133       {
00134         ch = *cp++;
00135         --compressedSize;
00136 
00137         if (ch & 0x80)
00138         {
00139           // replicate run
00140           if (compressedSize)
00141           {
00142             // DICOM packbit scheme uses 257 - nbytes to represent replicate runs
00143             nbytes = OFstatic_cast(unsigned char, 257 - ch);
00144             ch = *cp++;
00145             --compressedSize;
00146             replicate(ch, nbytes);
00147           }
00148           else
00149           {
00150             // suspension: replicate run but second byte is in next block
00151             suspendInfo_ = ch;
00152             result = EC_StreamNotifyClient;
00153           }
00154         } 
00155         else
00156         {
00157           // literal run
00158           nbytes = OFstatic_cast(unsigned char, (ch & 0x7f) + 1);
00159           if (compressedSize < nbytes)
00160           {
00161             // we're going to suspend, prepare everything
00162             suspendInfo_ = OFstatic_cast(unsigned char, nbytes - compressedSize - 1);
00163             nbytes = OFstatic_cast(unsigned char, compressedSize);
00164             result = EC_StreamNotifyClient;
00165           }
00166 
00167           literal(cp, nbytes);
00168           compressedSize -= nbytes;
00169           cp += nbytes;
00170         }
00171       }
00172 
00173       // failure status at this point means output buffer overflow
00174       if (fail_) result = EC_CorruptedData;
00175     }
00176 
00177     return result;
00178   }
00179 
00180 
00184   inline size_t size() const
00185   {
00186     return offset_;
00187   }
00188 
00191   inline void *getOutputBuffer() const
00192   {
00193     return outputBuffer_;
00194   }
00195 
00198   inline OFBool fail() const
00199   {
00200     if (fail_) return OFTrue; else return OFFalse;
00201   }
00202 
00203 private:
00204 
00206   DcmRLEDecoder(const DcmRLEDecoder&);
00207 
00209   DcmRLEDecoder& operator=(const DcmRLEDecoder&);
00210 
00211 
00216   inline void replicate(unsigned char ch, unsigned char nbytes)
00217   {
00218      if (offset_ + nbytes > outputBufferSize_)
00219      {
00220        // output buffer overflow
00221        fail_ = 1;
00222        nbytes = OFstatic_cast(unsigned char, outputBufferSize_ - offset_);
00223      }
00224 
00225      while (nbytes--) outputBuffer_[offset_++] = ch;
00226   }
00227 
00228 
00233   inline void literal(unsigned char *cp, unsigned char nbytes)
00234   {
00235      if (offset_ + nbytes > outputBufferSize_)
00236      {
00237        // output buffer overflow
00238        fail_ = 1;
00239        nbytes = OFstatic_cast(unsigned char, outputBufferSize_ - offset_);
00240      }
00241 
00242      while (nbytes--) outputBuffer_[offset_++] = *cp++;
00243   }
00244 
00245   /* member variables */
00246 
00251   int fail_;
00252 
00255   size_t outputBufferSize_;
00256 
00261   unsigned char *outputBuffer_;
00262 
00266   size_t offset_;
00267 
00273   unsigned char suspendInfo_;
00274 };
00275 
00276 #endif
00277 
00278 /*
00279  * CVS/RCS Log
00280  * $Log: dcrledec.h,v $
00281  * Revision 1.4  2005/12/08 16:28:36  meichel
00282  * Changed include path schema for all DCMTK header files
00283  *
00284  * Revision 1.3  2003/08/14 09:00:56  meichel
00285  * Adapted type casts to new-style typecast operators defined in ofcast.h
00286  *
00287  * Revision 1.2  2003/03/21 13:06:46  meichel
00288  * Minor code purifications for warnings reported by MSVC in Level 4
00289  *
00290  * Revision 1.1  2002/06/06 14:52:36  meichel
00291  * Initial release of the new RLE codec classes
00292  *   and the dcmcrle/dcmdrle tools in module dcmdata
00293  *
00294  *
00295  */


Generated on 20 Dec 2005 for OFFIS DCMTK Version 3.5.4 by Doxygen 1.4.5