1/////////////////////////////////////////////////////////////////////////// 2// 3// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas 4// Digital Ltd. LLC 5// 6// All rights reserved. 7// 8// Redistribution and use in source and binary forms, with or without 9// modification, are permitted provided that the following conditions are 10// met: 11// * Redistributions of source code must retain the above copyright 12// notice, this list of conditions and the following disclaimer. 13// * Redistributions in binary form must reproduce the above 14// copyright notice, this list of conditions and the following disclaimer 15// in the documentation and/or other materials provided with the 16// distribution. 17// * Neither the name of Industrial Light & Magic nor the names of 18// its contributors may be used to endorse or promote products derived 19// from this software without specific prior written permission. 20// 21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32// 33/////////////////////////////////////////////////////////////////////////// 34 35 36 37//----------------------------------------------------------------------------- 38// 39// class RleCompressor 40// 41//----------------------------------------------------------------------------- 42 43#include <ImfRleCompressor.h> 44#include <ImfCheckedArithmetic.h> 45#include "Iex.h" 46 47namespace Imf { 48namespace { 49 50const int MIN_RUN_LENGTH = 3; 51const int MAX_RUN_LENGTH = 127; 52 53 54// 55// Compress an array of bytes, using run-length encoding, 56// and return the length of the compressed data. 57// 58 59int 60rleCompress (int inLength, const char in[], signed char out[]) 61{ 62 const char *inEnd = in + inLength; 63 const char *runStart = in; 64 const char *runEnd = in + 1; 65 signed char *outWrite = out; 66 67 while (runStart < inEnd) 68 { 69 while (runEnd < inEnd && 70 *runStart == *runEnd && 71 runEnd - runStart - 1 < MAX_RUN_LENGTH) 72 { 73 ++runEnd; 74 } 75 76 if (runEnd - runStart >= MIN_RUN_LENGTH) 77 { 78 // 79 // Compressable run 80 // 81 82 *outWrite++ = (runEnd - runStart) - 1; 83 *outWrite++ = *(signed char *) runStart; 84 runStart = runEnd; 85 } 86 else 87 { 88 // 89 // Uncompressable run 90 // 91 92 while (runEnd < inEnd && 93 ((runEnd + 1 >= inEnd || 94 *runEnd != *(runEnd + 1)) || 95 (runEnd + 2 >= inEnd || 96 *(runEnd + 1) != *(runEnd + 2))) && 97 runEnd - runStart < MAX_RUN_LENGTH) 98 { 99 ++runEnd; 100 } 101 102 *outWrite++ = runStart - runEnd; 103 104 while (runStart < runEnd) 105 { 106 *outWrite++ = *(signed char *) (runStart++); 107 } 108 } 109 110 ++runEnd; 111 } 112 113 return outWrite - out; 114} 115 116 117// 118// Uncompress an array of bytes compressed with rleCompress(). 119// Returns the length of the oncompressed data, or 0 if the 120// length of the uncompressed data would be more than maxLength. 121// 122 123int 124rleUncompress (int inLength, int maxLength, const signed char in[], char out[]) 125{ 126 char *outStart = out; 127 128 while (inLength > 0) 129 { 130 if (*in < 0) 131 { 132 int count = -((int)*in++); 133 inLength -= count + 1; 134 135 if (0 > (maxLength -= count)) 136 return 0; 137 138 while (count-- > 0) 139 *out++ = *(char *) (in++); 140 } 141 else 142 { 143 int count = *in++; 144 inLength -= 2; 145 146 if (0 > (maxLength -= count + 1)) 147 return 0; 148 149 while (count-- >= 0) 150 *out++ = *(char *) in; 151 152 in++; 153 } 154 } 155 156 return out - outStart; 157} 158 159} // namespace 160 161 162RleCompressor::RleCompressor (const Header &hdr, size_t maxScanLineSize): 163 Compressor (hdr), 164 _maxScanLineSize (maxScanLineSize), 165 _tmpBuffer (0), 166 _outBuffer (0) 167{ 168 _tmpBuffer = new char [maxScanLineSize]; 169 _outBuffer = new char [uiMult (maxScanLineSize, size_t (3)) / 2]; 170} 171 172 173RleCompressor::~RleCompressor () 174{ 175 delete [] _tmpBuffer; 176 delete [] _outBuffer; 177} 178 179 180int 181RleCompressor::numScanLines () const 182{ 183 // 184 // This compressor compresses individual scan lines. 185 // 186 187 return 1; 188} 189 190 191int 192RleCompressor::compress (const char *inPtr, 193 int inSize, 194 int /*minY*/, 195 const char *&outPtr) 196{ 197 // 198 // Special case �- empty input buffer 199 // 200 201 if (inSize == 0) 202 { 203 outPtr = _outBuffer; 204 return 0; 205 } 206 207 // 208 // Reorder the pixel data. 209 // 210 211 { 212 char *t1 = _tmpBuffer; 213 char *t2 = _tmpBuffer + (inSize + 1) / 2; 214 const char *stop = inPtr + inSize; 215 216 while (true) 217 { 218 if (inPtr < stop) 219 *(t1++) = *(inPtr++); 220 else 221 break; 222 223 if (inPtr < stop) 224 *(t2++) = *(inPtr++); 225 else 226 break; 227 } 228 } 229 230 // 231 // Predictor. 232 // 233 234 { 235 unsigned char *t = (unsigned char *) _tmpBuffer + 1; 236 unsigned char *stop = (unsigned char *) _tmpBuffer + inSize; 237 int p = t[-1]; 238 239 while (t < stop) 240 { 241 int d = int (t[0]) - p + (128 + 256); 242 p = t[0]; 243 t[0] = d; 244 ++t; 245 } 246 } 247 248 // 249 // Run-length encode the data. 250 // 251 252 outPtr = _outBuffer; 253 return rleCompress (inSize, _tmpBuffer, (signed char *) _outBuffer); 254} 255 256 257int 258RleCompressor::uncompress (const char *inPtr, 259 int inSize, 260 int /*minY*/, 261 const char *&outPtr) 262{ 263 // 264 // Special case �- empty input buffer 265 // 266 267 if (inSize == 0) 268 { 269 outPtr = _outBuffer; 270 return 0; 271 } 272 273 // 274 // Decode the run-length encoded data 275 // 276 277 int outSize; 278 279 if (0 == (outSize = rleUncompress (inSize, _maxScanLineSize, 280 (const signed char *) inPtr, 281 _tmpBuffer))) 282 { 283 throw Iex::InputExc ("Data decoding (rle) failed."); 284 } 285 286 // 287 // Predictor. 288 // 289 290 { 291 unsigned char *t = (unsigned char *) _tmpBuffer + 1; 292 unsigned char *stop = (unsigned char *) _tmpBuffer + outSize; 293 294 while (t < stop) 295 { 296 int d = int (t[-1]) + int (t[0]) - 128; 297 t[0] = d; 298 ++t; 299 } 300 } 301 302 // 303 // Reorder the pixel data. 304 // 305 306 { 307 const char *t1 = _tmpBuffer; 308 const char *t2 = _tmpBuffer + (outSize + 1) / 2; 309 char *s = _outBuffer; 310 char *stop = s + outSize; 311 312 while (true) 313 { 314 if (s < stop) 315 *(s++) = *(t1++); 316 else 317 break; 318 319 if (s < stop) 320 *(s++) = *(t2++); 321 else 322 break; 323 } 324 } 325 326 outPtr = _outBuffer; 327 return outSize; 328} 329 330 331} // namespace Imf 332