1 /*
2 ** SPDX-License-Identifier: BSD-3-Clause
3 ** Copyright Contributors to the OpenEXR Project.
4 */
5 
6 #include "internal_compress.h"
7 #include "internal_decompress.h"
8 
9 #include "internal_coding.h"
10 
11 #include <stdio.h>
12 #include <string.h>
13 
14 #define MIN_RUN_LENGTH 3
15 #define MAX_RUN_LENGTH 127
16 
17 uint64_t
internal_rle_compress(void * out,uint64_t outbytes,const void * src,uint64_t srcbytes)18 internal_rle_compress (
19     void* out, uint64_t outbytes, const void* src, uint64_t srcbytes)
20 {
21     int8_t*       cbuf = out;
22     const int8_t* runs = src;
23     const int8_t* end  = runs + srcbytes;
24     const int8_t* rune = runs + 1;
25     uint64_t      outb = 0;
26 
27     while (runs < end)
28     {
29         uint8_t curcount = 0;
30         while (rune < end && *runs == *rune && curcount < MAX_RUN_LENGTH)
31         {
32             ++rune;
33             ++curcount;
34         }
35 
36         if (curcount >= (MIN_RUN_LENGTH - 1))
37         {
38             cbuf[outb++] = (int8_t) curcount;
39             cbuf[outb++] = *runs;
40 
41             runs = rune;
42         }
43         else
44         {
45             /* uncompressable */
46             ++curcount;
47             while (rune < end &&
48                    ((rune + 1 >= end || *rune != *(rune + 1)) ||
49                     (rune + 2 >= end || *(rune + 1) != *(rune + 2))) &&
50                    curcount < MAX_RUN_LENGTH)
51             {
52                 ++curcount;
53                 ++rune;
54             }
55             cbuf[outb++] = (int8_t) (-((int) curcount));
56             while (runs < rune)
57                 cbuf[outb++] = *runs++;
58         }
59         ++rune;
60         if (outb >= outbytes) break;
61     }
62     return outb;
63 }
64 
65 /**************************************/
66 
67 static void
reorder_and_predict(void * scratch,const void * packed,uint64_t packedbytes)68 reorder_and_predict (void* scratch, const void* packed, uint64_t packedbytes)
69 {
70     int8_t*       t1   = scratch;
71     int8_t*       t2   = t1 + (packedbytes + 1) / 2;
72     const int8_t* in   = packed;
73     const int8_t* stop = in + packedbytes;
74     while (in < stop)
75     {
76         *(t1++) = *(in++);
77         if (in < stop) *(t2++) = *(in++);
78     }
79 
80     t1    = scratch;
81     stop  = t1 + packedbytes;
82     int p = *(t1++);
83     while (t1 < stop)
84     {
85         int d = (int) (*t1) - p + (128 + 256);
86         p     = *t1;
87         *t1++ = (int8_t) (d);
88     }
89 }
90 
91 exr_result_t
internal_exr_apply_rle(exr_encode_pipeline_t * encode)92 internal_exr_apply_rle (exr_encode_pipeline_t* encode)
93 {
94     exr_result_t rv;
95     uint64_t     outb, srcb;
96 
97     srcb = encode->packed_bytes;
98 
99     rv = internal_encode_alloc_buffer (
100         encode,
101         EXR_TRANSCODE_BUFFER_SCRATCH1,
102         &(encode->scratch_buffer_1),
103         &(encode->scratch_alloc_size_1),
104         srcb);
105     if (rv != EXR_ERR_SUCCESS) return rv;
106 
107     reorder_and_predict (encode->scratch_buffer_1, encode->packed_buffer, srcb);
108 
109     outb = internal_rle_compress (
110         encode->compressed_buffer,
111         encode->compressed_alloc_size,
112         encode->scratch_buffer_1,
113         srcb);
114 
115     if (outb >= srcb)
116     {
117         memcpy (encode->compressed_buffer, encode->packed_buffer, srcb);
118         outb = srcb;
119     }
120     encode->compressed_bytes = outb;
121     return EXR_ERR_SUCCESS;
122 }
123 
124 /**************************************/
125 
126 uint64_t
internal_rle_decompress(uint8_t * out,uint64_t outsz,const uint8_t * src,uint64_t packsz)127 internal_rle_decompress (
128     uint8_t* out, uint64_t outsz, const uint8_t* src, uint64_t packsz)
129 {
130     const int8_t* in          = (const int8_t*) src;
131     uint8_t*      dst         = (uint8_t*) out;
132     uint64_t      unpackbytes = 0;
133     uint64_t      outbytes    = 0;
134 
135     while (unpackbytes < packsz)
136     {
137         if (*in < 0)
138         {
139             uint64_t count = (uint64_t) (-((int) *in++));
140             ++unpackbytes;
141             if (unpackbytes + count > packsz) return EXR_ERR_CORRUPT_CHUNK;
142             if (outbytes + count > outsz) return EXR_ERR_CORRUPT_CHUNK;
143 
144             memcpy (dst, in, count);
145             in += count;
146             dst += count;
147             unpackbytes += count;
148             outbytes += count;
149         }
150         else
151         {
152             uint64_t count = (uint64_t) (*in++);
153             if (unpackbytes + 2 > packsz) return EXR_ERR_CORRUPT_CHUNK;
154             unpackbytes += 2;
155 
156             ++count;
157             if (outbytes + count > outsz) return EXR_ERR_CORRUPT_CHUNK;
158 
159             memset (dst, *(const uint8_t*) in, count);
160             dst += count;
161             outbytes += count;
162             ++in;
163         }
164     }
165     return outbytes;
166 }
167 
168 static void
unpredict_and_reorder(void * out,void * scratch,uint64_t packedbytes)169 unpredict_and_reorder (void* out, void* scratch, uint64_t packedbytes)
170 {
171     int8_t*       t1   = scratch;
172     int8_t*       t2   = t1 + (packedbytes + 1) / 2;
173     int8_t*       s    = out;
174     const int8_t* stop = t1 + packedbytes;
175 
176     ++t1;
177     while (t1 < stop)
178     {
179         int d = (int) (t1[-1]) + (int) (t1[0]) - 128;
180         t1[0] = (int8_t)d;
181         ++t1;
182     }
183 
184     t1   = scratch;
185     stop = s + packedbytes;
186     while (s < stop)
187     {
188         *(s++) = *(t1++);
189         if (s < stop) *(s++) = *(t2++);
190     }
191 }
192 
193 exr_result_t
internal_exr_undo_rle(exr_decode_pipeline_t * decode,const void * src,uint64_t packsz,void * out,uint64_t outsz)194 internal_exr_undo_rle (
195     exr_decode_pipeline_t* decode,
196     const void*            src,
197     uint64_t               packsz,
198     void*                  out,
199     uint64_t               outsz)
200 {
201     exr_result_t rv;
202     uint64_t     unpackb;
203     rv = internal_decode_alloc_buffer (
204         decode,
205         EXR_TRANSCODE_BUFFER_SCRATCH1,
206         &(decode->scratch_buffer_1),
207         &(decode->scratch_alloc_size_1),
208         outsz);
209     if (rv != EXR_ERR_SUCCESS) return rv;
210 
211     unpackb =
212         internal_rle_decompress (decode->scratch_buffer_1, outsz, src, packsz);
213     if (unpackb != outsz) return EXR_ERR_CORRUPT_CHUNK;
214 
215     unpredict_and_reorder (out, decode->scratch_buffer_1, outsz);
216     return EXR_ERR_SUCCESS;
217 }
218