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