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 "Iex.h"
45
46namespace Imf {
47namespace {
48
49const int MIN_RUN_LENGTH = 3;
50const int MAX_RUN_LENGTH = 127;
51
52
53//
54// Compress an array of bytes, using run-length encoding,
55// and return the length of the compressed data.
56//
57
58int
59rleCompress (int inLength, const char in[], signed char out[])
60{
61    const char *inEnd = in + inLength;
62    const char *runStart = in;
63    const char *runEnd = in + 1;
64    signed char *outWrite = out;
65
66    while (runStart < inEnd)
67    {
68	while (runEnd < inEnd &&
69	       *runStart == *runEnd &&
70	       runEnd - runStart - 1 < MAX_RUN_LENGTH)
71	{
72	    ++runEnd;
73	}
74
75	if (runEnd - runStart >= MIN_RUN_LENGTH)
76	{
77	    //
78	    // Compressable run
79	    //
80
81	    *outWrite++ = (runEnd - runStart) - 1;
82	    *outWrite++ = *(signed char *) runStart;
83	    runStart = runEnd;
84	}
85	else
86	{
87	    //
88	    // Uncompressable run
89	    //
90
91	    while (runEnd < inEnd &&
92		   ((runEnd + 1 >= inEnd ||
93		     *runEnd != *(runEnd + 1)) ||
94		    (runEnd + 2 >= inEnd ||
95		     *(runEnd + 1) != *(runEnd + 2))) &&
96		   runEnd - runStart < MAX_RUN_LENGTH)
97	    {
98		++runEnd;
99	    }
100
101	    *outWrite++ = runStart - runEnd;
102
103	    while (runStart < runEnd)
104	    {
105		*outWrite++ = *(signed char *) (runStart++);
106	    }
107	}
108
109	++runEnd;
110    }
111
112    return outWrite - out;
113}
114
115
116//
117// Uncompress an array of bytes compressed with rleCompress().
118// Returns the length of the oncompressed data, or 0 if the
119// length of the uncompressed data would be more than maxLength.
120//
121
122int
123rleUncompress (int inLength, int maxLength, const signed char in[], char out[])
124{
125    char *outStart = out;
126
127    while (inLength > 0)
128    {
129	if (*in < 0)
130	{
131	    int count = -((int)*in++);
132	    inLength -= count + 1;
133
134	    if (0 > (maxLength -= count))
135		return 0;
136
137	    while (count-- > 0)
138		*out++ = *(char *) (in++);
139	}
140	else
141	{
142	    int count = *in++;
143	    inLength -= 2;
144
145	    if (0 > (maxLength -= count + 1))
146		return 0;
147
148	    while (count-- >= 0)
149		*out++ = *(char *) in;
150
151	    in++;
152	}
153    }
154
155    return out - outStart;
156}
157
158} // namespace
159
160
161RleCompressor::RleCompressor (const Header &hdr, int maxScanLineSize):
162    Compressor (hdr),
163    _maxScanLineSize (maxScanLineSize),
164    _tmpBuffer (0),
165    _outBuffer (0)
166{
167    _tmpBuffer = new char [maxScanLineSize];
168    _outBuffer = new char [maxScanLineSize * 3 / 2];
169}
170
171
172RleCompressor::~RleCompressor ()
173{
174    delete [] _tmpBuffer;
175    delete [] _outBuffer;
176}
177
178
179int
180RleCompressor::numScanLines () const
181{
182    //
183    // This compressor compresses individual scan lines.
184    //
185
186    return 1;
187}
188
189
190int
191RleCompressor::compress (const char *inPtr,
192			 int inSize,
193			 int minY,
194			 const char *&outPtr)
195{
196    //
197    // Special case �- empty input buffer
198    //
199
200    if (inSize == 0)
201    {
202	outPtr = _outBuffer;
203	return 0;
204    }
205
206    //
207    // Reorder the pixel data.
208    //
209
210    {
211	char *t1 = _tmpBuffer;
212	char *t2 = _tmpBuffer + (inSize + 1) / 2;
213	const char *stop = inPtr + inSize;
214
215	while (true)
216	{
217	    if (inPtr < stop)
218		*(t1++) = *(inPtr++);
219	    else
220		break;
221
222	    if (inPtr < stop)
223		*(t2++) = *(inPtr++);
224	    else
225		break;
226	}
227    }
228
229    //
230    // Predictor.
231    //
232
233    {
234	unsigned char *t = (unsigned char *) _tmpBuffer + 1;
235	unsigned char *stop = (unsigned char *) _tmpBuffer + inSize;
236	int p = t[-1];
237
238	while (t < stop)
239	{
240	    int d = int (t[0]) - p + (128 + 256);
241	    p = t[0];
242	    t[0] = d;
243	    ++t;
244	}
245    }
246
247    //
248    // Run-length encode the data.
249    //
250
251    outPtr = _outBuffer;
252    return rleCompress (inSize, _tmpBuffer, (signed char *) _outBuffer);
253}
254
255
256int
257RleCompressor::uncompress (const char *inPtr,
258			   int inSize,
259			   int minY,
260			   const char *&outPtr)
261{
262    //
263    // Special case �- empty input buffer
264    //
265
266    if (inSize == 0)
267    {
268	outPtr = _outBuffer;
269	return 0;
270    }
271
272    //
273    // Decode the run-length encoded data
274    //
275
276    int outSize;
277
278    if (0 == (outSize = rleUncompress (inSize, _maxScanLineSize,
279				       (const signed char *) inPtr,
280				       _tmpBuffer)))
281    {
282	throw Iex::InputExc ("Data decoding (rle) failed.");
283    }
284
285    //
286    // Predictor.
287    //
288
289    {
290	unsigned char *t = (unsigned char *) _tmpBuffer + 1;
291	unsigned char *stop = (unsigned char *) _tmpBuffer + outSize;
292
293	while (t < stop)
294	{
295	    int d = int (t[-1]) + int (t[0]) - 128;
296	    t[0] = d;
297	    ++t;
298	}
299    }
300
301    //
302    // Reorder the pixel data.
303    //
304
305    {
306	const char *t1 = _tmpBuffer;
307	const char *t2 = _tmpBuffer + (outSize + 1) / 2;
308	char *s = _outBuffer;
309	char *stop = s + outSize;
310
311	while (true)
312	{
313	    if (s < stop)
314		*(s++) = *(t1++);
315	    else
316		break;
317
318	    if (s < stop)
319		*(s++) = *(t2++);
320	    else
321		break;
322	}
323    }
324
325    outPtr = _outBuffer;
326    return outSize;
327}
328
329
330} // namespace Imf
331