• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
47 namespace Imf {
48 namespace {
49 
50 const int MIN_RUN_LENGTH = 3;
51 const 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 
59 int
rleCompress(int inLength,const char in[],signed char out[])60 rleCompress (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 
123 int
rleUncompress(int inLength,int maxLength,const signed char in[],char out[])124 rleUncompress (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 
RleCompressor(const Header & hdr,size_t maxScanLineSize)162 RleCompressor::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 
~RleCompressor()173 RleCompressor::~RleCompressor ()
174 {
175     delete [] _tmpBuffer;
176     delete [] _outBuffer;
177 }
178 
179 
180 int
numScanLines() const181 RleCompressor::numScanLines () const
182 {
183     //
184     // This compressor compresses individual scan lines.
185     //
186 
187     return 1;
188 }
189 
190 
191 int
compress(const char * inPtr,int inSize,int,const char * & outPtr)192 RleCompressor::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 
257 int
uncompress(const char * inPtr,int inSize,int,const char * & outPtr)258 RleCompressor::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