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