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 */