dcmdata/include/dcmtk/dcmdata/dcrledec.h

00001 /*
00002  *
00003  *  Copyright (C) 1994-2010, OFFIS e.V.
00004  *  All rights reserved.  See COPYRIGHT file for details.
00005  *
00006  *  This software and supporting documentation were developed by
00007  *
00008  *    OFFIS e.V.
00009  *    R&D Division Health
00010  *    Escherweg 2
00011  *    D-26121 Oldenburg, Germany
00012  *
00013  *
00014  *  Module:  dcmdata
00015  *
00016  *  Author:  Marco Eichelberg
00017  *
00018  *  Purpose: RLE decompressor
00019  *
00020  *  Last Update:      $Author: joergr $
00021  *  Update Date:      $Date: 2010-10-14 13:15:42 $
00022  *  CVS/RCS Revision: $Revision: 1.6 $
00023  *  Status:           $State: Exp $
00024  *
00025  *  CVS/RCS Log at end of file
00026  *
00027  */
00028 
00029 #ifndef DCRLEDEC_H
00030 #define DCRLEDEC_H
00031 
00032 #include "dcmtk/config/osconfig.h"
00033 #include "dcmtk/dcmdata/dcerror.h"
00034 
00038 class DcmRLEDecoder
00039 {
00040 public:
00041 
00046   DcmRLEDecoder(size_t outputBufferSize)
00047   : fail_(0)
00048   , outputBufferSize_(outputBufferSize)
00049   , outputBuffer_(NULL)
00050   , offset_(0)
00051   , suspendInfo_(128)
00052   {
00053     if (outputBufferSize_ == 0) fail_ = 1;
00054     else
00055     {
00056       outputBuffer_ = new unsigned char[outputBufferSize_];
00057       if (outputBuffer_ == NULL) fail_ = 1;
00058     }
00059   }
00060 
00062   ~DcmRLEDecoder()
00063   {
00064     delete[] outputBuffer_;
00065   }
00066 
00070   inline void clear()
00071   {
00072     offset_ = 0;
00073     suspendInfo_ = 128;
00074     if (outputBuffer_) fail_ = 0;
00075   }
00076 
00077 
00078   inline OFCondition decompress(void *compressedData, size_t compressedSize)
00079   {
00080     // we allow a call for zero bytes
00081     if (compressedSize == 0) return EC_Normal;
00082 
00083     OFCondition result = EC_IllegalCall;
00084 
00085     // check parameters passed by caller
00086     if (compressedData == NULL) fail_ = 1;
00087 
00088     if (! fail_)  // if fail_ is true, just ignore input
00089     {
00090       result = EC_Normal;
00091       unsigned char ch;
00092       unsigned char nbytes;
00093       unsigned char *cp = OFstatic_cast(unsigned char *, compressedData);
00094 
00095       // check if we suspended last time, clean up
00096       if (suspendInfo_ > 128)
00097       {
00098         // DICOM packbit scheme uses 257 - nbytes to represent replicate runs
00099         nbytes = OFstatic_cast(unsigned char, 257 - suspendInfo_);
00100 
00101         // suspended replicate run. compressedSize cannot be zero now.
00102         suspendInfo_ = 128;
00103 
00104         ch = *cp++;
00105         --compressedSize;
00106         replicate(ch, nbytes);
00107       }
00108       else if (suspendInfo_ < 128)
00109       {
00110         // suspended literal run
00111         nbytes = OFstatic_cast(unsigned char, (suspendInfo_ & 0x7f) + 1);
00112         suspendInfo_ = 128;
00113         if (compressedSize < nbytes)
00114         {
00115           // we're going to suspend again (oops?), prepare everything
00116           suspendInfo_ = OFstatic_cast(unsigned char, nbytes - compressedSize - 1);
00117           nbytes = OFstatic_cast(unsigned char, compressedSize);
00118           result = EC_StreamNotifyClient;
00119         }
00120 
00121         literal(cp, nbytes);
00122         compressedSize -= nbytes;
00123         cp += nbytes;
00124       }
00125 
00126       // continue with ordinary RLE decompression
00127       while (compressedSize && (! fail_))
00128       {
00129         ch = *cp++;
00130         --compressedSize;
00131 
00132         if (ch & 0x80)
00133         {
00134           // replicate run
00135           if (compressedSize)
00136           {
00137             // DICOM packbit scheme uses 257 - nbytes to represent replicate runs
00138             nbytes = OFstatic_cast(unsigned char, 257 - ch);
00139             ch = *cp++;
00140             --compressedSize;
00141             replicate(ch, nbytes);
00142           }
00143           else
00144           {
00145             // suspension: replicate run but second byte is in next block
00146             suspendInfo_ = ch;
00147             result = EC_StreamNotifyClient;
00148           }
00149         } 
00150         else
00151         {
00152           // literal run
00153           nbytes = OFstatic_cast(unsigned char, (ch & 0x7f) + 1);
00154           if (compressedSize < nbytes)
00155           {
00156             // we're going to suspend, prepare everything
00157             suspendInfo_ = OFstatic_cast(unsigned char, nbytes - compressedSize - 1);
00158             nbytes = OFstatic_cast(unsigned char, compressedSize);
00159             result = EC_StreamNotifyClient;
00160           }
00161 
00162           literal(cp, nbytes);
00163           compressedSize -= nbytes;
00164           cp += nbytes;
00165         }
00166       }
00167 
00168       // failure status at this point means output buffer overflow
00169       if (fail_) result = EC_CorruptedData;
00170     }
00171 
00172     return result;
00173   }
00174 
00175 
00179   inline size_t size() const
00180   {
00181     return offset_;
00182   }
00183 
00186   inline void *getOutputBuffer() const
00187   {
00188     return outputBuffer_;
00189   }
00190 
00193   inline OFBool fail() const
00194   {
00195     if (fail_) return OFTrue; else return OFFalse;
00196   }
00197 
00198 private:
00199 
00201   DcmRLEDecoder(const DcmRLEDecoder&);
00202 
00204   DcmRLEDecoder& operator=(const DcmRLEDecoder&);
00205 
00206 
00211   inline void replicate(unsigned char ch, unsigned char nbytes)
00212   {
00213      if (offset_ + nbytes > outputBufferSize_)
00214      {
00215        // output buffer overflow
00216        fail_ = 1;
00217        nbytes = OFstatic_cast(unsigned char, outputBufferSize_ - offset_);
00218      }
00219 
00220      while (nbytes--) outputBuffer_[offset_++] = ch;
00221   }
00222 
00223 
00228   inline void literal(unsigned char *cp, unsigned char nbytes)
00229   {
00230      if (offset_ + nbytes > outputBufferSize_)
00231      {
00232        // output buffer overflow
00233        fail_ = 1;
00234        nbytes = OFstatic_cast(unsigned char, outputBufferSize_ - offset_);
00235      }
00236 
00237      while (nbytes--) outputBuffer_[offset_++] = *cp++;
00238   }
00239 
00240   /* member variables */
00241 
00246   int fail_;
00247 
00250   size_t outputBufferSize_;
00251 
00256   unsigned char *outputBuffer_;
00257 
00261   size_t offset_;
00262 
00268   unsigned char suspendInfo_;
00269 };
00270 
00271 #endif
00272 
00273 /*
00274  * CVS/RCS Log
00275  * $Log: dcrledec.h,v $
00276  * Revision 1.6  2010-10-14 13:15:42  joergr
00277  * Updated copyright header. Added reference to COPYRIGHT file.
00278  *
00279  * Revision 1.5  2009-11-04 09:58:07  uli
00280  * Switched to logging mechanism provided by the "new" oflog module
00281  *
00282  * Revision 1.4  2005-12-08 16:28:36  meichel
00283  * Changed include path schema for all DCMTK header files
00284  *
00285  * Revision 1.3  2003/08/14 09:00:56  meichel
00286  * Adapted type casts to new-style typecast operators defined in ofcast.h
00287  *
00288  * Revision 1.2  2003/03/21 13:06:46  meichel
00289  * Minor code purifications for warnings reported by MSVC in Level 4
00290  *
00291  * Revision 1.1  2002/06/06 14:52:36  meichel
00292  * Initial release of the new RLE codec classes
00293  *   and the dcmcrle/dcmdrle tools in module dcmdata
00294  *
00295  *
00296  */


Generated on 6 Jan 2011 for OFFIS DCMTK Version 3.6.0 by Doxygen 1.5.1