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