1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright (c) Contributors to the OpenEXR Project.
4 //
5
6 #include <string.h>
7 #include "ImfRle.h"
8 #include "ImfNamespace.h"
9
10 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
11
12 namespace {
13
14 const int MIN_RUN_LENGTH = 3;
15 const int MAX_RUN_LENGTH = 127;
16
17 }
18
19 //
20 // Compress an array of bytes, using run-length encoding,
21 // and return the length of the compressed data.
22 //
23
24 int
rleCompress(int inLength,const char in[],signed char out[])25 rleCompress (int inLength, const char in[], signed char out[])
26 {
27 const char *inEnd = in + inLength;
28 const char *runStart = in;
29 const char *runEnd = in + 1;
30 signed char *outWrite = out;
31
32 while (runStart < inEnd)
33 {
34 while (runEnd < inEnd &&
35 *runStart == *runEnd &&
36 runEnd - runStart - 1 < MAX_RUN_LENGTH)
37 {
38 ++runEnd;
39 }
40
41 if (runEnd - runStart >= MIN_RUN_LENGTH)
42 {
43 //
44 // Compressable run
45 //
46
47 *outWrite++ = (runEnd - runStart) - 1;
48 *outWrite++ = *(signed char *) runStart;
49 runStart = runEnd;
50 }
51 else
52 {
53 //
54 // Uncompressable run
55 //
56
57 while (runEnd < inEnd &&
58 ((runEnd + 1 >= inEnd ||
59 *runEnd != *(runEnd + 1)) ||
60 (runEnd + 2 >= inEnd ||
61 *(runEnd + 1) != *(runEnd + 2))) &&
62 runEnd - runStart < MAX_RUN_LENGTH)
63 {
64 ++runEnd;
65 }
66
67 *outWrite++ = runStart - runEnd;
68
69 while (runStart < runEnd)
70 {
71 *outWrite++ = *(signed char *) (runStart++);
72 }
73 }
74
75 ++runEnd;
76 }
77
78 return outWrite - out;
79 }
80
81
82 //
83 // Uncompress an array of bytes compressed with rleCompress().
84 // Returns the length of the oncompressed data, or 0 if the
85 // length of the uncompressed data would be more than maxLength.
86 //
87
88 int
rleUncompress(int inLength,int maxLength,const signed char in[],char out[])89 rleUncompress (int inLength, int maxLength, const signed char in[], char out[])
90 {
91 char *outStart = out;
92
93 while (inLength > 0)
94 {
95 if (*in < 0)
96 {
97 int count = -((int)*in++);
98 inLength -= count + 1;
99
100 if (0 > (maxLength -= count))
101 return 0;
102
103 // check the input buffer is big enough to contain
104 // 'count' bytes of remaining data
105 if (inLength < 0)
106 return 0;
107
108 memcpy(out, in, count);
109 out += count;
110 in += count;
111 }
112 else
113 {
114 int count = *in++;
115 inLength -= 2;
116
117 if (0 > (maxLength -= count + 1))
118 return 0;
119
120 // check the input buffer is big enough to contain
121 // byte to be duplicated
122 if (inLength < 0)
123 return 0;
124
125 memset(out, *(char*)in, count+1);
126 out += count+1;
127
128 in++;
129 }
130 }
131
132 return out - outStart;
133 }
134
135
136
137
138 OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
139