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