/src/gdal/third_party/LercLib/RLE.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright 2015 Esri |
3 | | |
4 | | Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | you may not use this file except in compliance with the License. |
6 | | You may obtain a copy of the License at |
7 | | |
8 | | http://www.apache.org/licenses/LICENSE-2.0 |
9 | | |
10 | | Unless required by applicable law or agreed to in writing, software |
11 | | distributed under the License is distributed on an "AS IS" BASIS, |
12 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | See the License for the specific language governing permissions and |
14 | | limitations under the License. |
15 | | |
16 | | A local copy of the license and additional notices are located with the |
17 | | source distribution at: |
18 | | |
19 | | http://github.com/Esri/lerc/ |
20 | | |
21 | | Contributors: Thomas Maurer |
22 | | */ |
23 | | |
24 | | #include "Defines.h" |
25 | | #include "RLE.h" |
26 | | #include <cstring> |
27 | | |
28 | | USING_NAMESPACE_LERC |
29 | | |
30 | | // -------------------------------------------------------------------------- ; |
31 | | |
32 | | size_t RLE::computeNumBytesRLE(const Byte* arr, size_t numBytes) const |
33 | 0 | { |
34 | 0 | if (arr == nullptr || numBytes == 0) |
35 | 0 | return 0; |
36 | | |
37 | 0 | const Byte* ptr = arr; |
38 | 0 | size_t sum = 0; |
39 | 0 | size_t cntOdd = 0; |
40 | 0 | size_t cntEven = 0; |
41 | 0 | size_t cntTotal = 0; |
42 | 0 | bool bOdd = true; |
43 | |
|
44 | 0 | while (cntTotal < numBytes - 1) |
45 | 0 | { |
46 | 0 | if (*ptr != *(ptr + 1)) |
47 | 0 | { |
48 | 0 | if (bOdd) |
49 | 0 | { |
50 | 0 | cntOdd++; |
51 | 0 | } |
52 | 0 | else // switch to odd mode |
53 | 0 | { |
54 | 0 | sum += 2 + 1; |
55 | 0 | bOdd = true; |
56 | 0 | cntOdd = 0; |
57 | 0 | cntEven = 0; |
58 | 0 | } |
59 | 0 | } |
60 | 0 | else |
61 | 0 | { |
62 | 0 | if (!bOdd) |
63 | 0 | { |
64 | 0 | cntEven++; |
65 | 0 | } |
66 | 0 | else |
67 | 0 | { |
68 | | // count if we have enough equal bytes so it is worth switching to even |
69 | 0 | bool foundEnough = false; |
70 | 0 | if (cntTotal + m_minNumEven < numBytes) |
71 | 0 | { |
72 | 0 | int i = 1; |
73 | 0 | while (i < m_minNumEven && ptr[i] == ptr[0]) i++; |
74 | 0 | foundEnough = i < m_minNumEven ? false : true; |
75 | 0 | } |
76 | |
|
77 | 0 | if (!foundEnough) // stay in odd mode |
78 | 0 | { |
79 | 0 | cntOdd++; |
80 | 0 | } |
81 | 0 | else // switch to even mode |
82 | 0 | { |
83 | 0 | if (cntOdd > 0) |
84 | 0 | sum += 2 + cntOdd; |
85 | 0 | bOdd = false; |
86 | 0 | cntOdd = 0; |
87 | 0 | cntEven = 0; |
88 | 0 | cntEven++; |
89 | 0 | } |
90 | 0 | } |
91 | 0 | } |
92 | 0 | ptr++; |
93 | 0 | cntTotal++; |
94 | |
|
95 | 0 | if (cntOdd == 32767) // prevent short counters from overflow |
96 | 0 | { |
97 | 0 | sum += 2 + 32767; |
98 | 0 | cntOdd = 0; |
99 | 0 | } |
100 | 0 | if (cntEven == 32767) |
101 | 0 | { |
102 | 0 | sum += 2 + 1; |
103 | 0 | cntEven = 0; |
104 | 0 | } |
105 | 0 | } |
106 | | |
107 | | // don't forget the last byte |
108 | 0 | if (bOdd) |
109 | 0 | { |
110 | 0 | cntOdd++; |
111 | 0 | sum += 2 + cntOdd; |
112 | 0 | } |
113 | 0 | else |
114 | 0 | { |
115 | 0 | sum += 2 + 1; |
116 | 0 | } |
117 | |
|
118 | 0 | return sum + 2; // EOF short |
119 | 0 | } |
120 | | |
121 | | // -------------------------------------------------------------------------- ; |
122 | | |
123 | | bool RLE::compress(const Byte* arr, size_t numBytes, |
124 | | Byte** arrRLE, size_t& numBytesRLE, bool verify) const |
125 | 0 | { |
126 | 0 | if (arr == nullptr || numBytes == 0) |
127 | 0 | return false; |
128 | | |
129 | 0 | numBytesRLE = computeNumBytesRLE(arr, numBytes); |
130 | |
|
131 | 0 | *arrRLE = new Byte[numBytesRLE]; |
132 | 0 | if (!*arrRLE) |
133 | 0 | return false; |
134 | | |
135 | 0 | const Byte* srcPtr = arr; |
136 | 0 | Byte* cntPtr = *arrRLE; |
137 | 0 | Byte* dstPtr = cntPtr + 2; |
138 | | //size_t sum = 0; |
139 | 0 | size_t cntOdd = 0; |
140 | 0 | size_t cntEven = 0; |
141 | 0 | size_t cntTotal = 0; |
142 | 0 | bool bOdd = true; |
143 | |
|
144 | 0 | while (cntTotal < numBytes - 1) |
145 | 0 | { |
146 | 0 | if (*srcPtr != *(srcPtr + 1)) |
147 | 0 | { |
148 | 0 | *dstPtr++ = *srcPtr; |
149 | 0 | if (bOdd) |
150 | 0 | { |
151 | 0 | cntOdd++; |
152 | 0 | } |
153 | 0 | else // switch to odd mode |
154 | 0 | { |
155 | 0 | cntEven++; |
156 | 0 | writeCount(-(short)cntEven, &cntPtr, &dstPtr); // - sign for even cnts |
157 | | //sum += 2 + 1; |
158 | 0 | bOdd = true; |
159 | 0 | cntOdd = 0; |
160 | 0 | cntEven = 0; |
161 | 0 | } |
162 | 0 | } |
163 | 0 | else |
164 | 0 | { |
165 | 0 | if (!bOdd) |
166 | 0 | { |
167 | 0 | cntEven++; |
168 | 0 | } |
169 | 0 | else |
170 | 0 | { |
171 | | // count if we have enough equal bytes so it is worth switching to even |
172 | 0 | bool foundEnough = false; |
173 | 0 | if (cntTotal + m_minNumEven < numBytes) |
174 | 0 | { |
175 | 0 | int i = 1; |
176 | 0 | while (i < m_minNumEven && srcPtr[i] == srcPtr[0]) i++; |
177 | 0 | foundEnough = i < m_minNumEven ? false : true; |
178 | 0 | } |
179 | |
|
180 | 0 | if (!foundEnough) // stay in odd mode |
181 | 0 | { |
182 | 0 | *dstPtr++ = *srcPtr; |
183 | 0 | cntOdd++; |
184 | 0 | } |
185 | 0 | else // switch to even mode |
186 | 0 | { |
187 | 0 | if (cntOdd > 0) |
188 | 0 | { |
189 | 0 | writeCount((short)cntOdd, &cntPtr, &dstPtr); // + sign for odd cnts |
190 | | //sum += 2 + cntOdd; |
191 | 0 | } |
192 | 0 | bOdd = false; |
193 | 0 | cntOdd = 0; |
194 | 0 | cntEven = 0; |
195 | 0 | cntEven++; |
196 | 0 | } |
197 | 0 | } |
198 | 0 | } |
199 | |
|
200 | 0 | if (cntOdd == 32767) // prevent short counters from overflow |
201 | 0 | { |
202 | 0 | writeCount((short)cntOdd, &cntPtr, &dstPtr); |
203 | | //sum += 2 + 32767; |
204 | 0 | cntOdd = 0; |
205 | 0 | } |
206 | 0 | if (cntEven == 32767) |
207 | 0 | { |
208 | 0 | *dstPtr++ = *srcPtr; |
209 | 0 | writeCount(-(short)cntEven, &cntPtr, &dstPtr); |
210 | | //sum += 2 + 1; |
211 | 0 | cntEven = 0; |
212 | 0 | } |
213 | |
|
214 | 0 | srcPtr++; |
215 | 0 | cntTotal++; |
216 | 0 | } |
217 | | |
218 | | // don't forget the last byte |
219 | 0 | *dstPtr++ = *srcPtr; |
220 | 0 | if (bOdd) |
221 | 0 | { |
222 | 0 | cntOdd++; |
223 | 0 | writeCount((short)cntOdd, &cntPtr, &dstPtr); |
224 | | //sum += 2 + cntOdd; |
225 | 0 | } |
226 | 0 | else |
227 | 0 | { |
228 | 0 | cntEven++; |
229 | 0 | writeCount(-(short)cntEven, &cntPtr, &dstPtr); |
230 | | //sum += 2 + 1; |
231 | 0 | } |
232 | |
|
233 | 0 | writeCount(-32768, &cntPtr, &dstPtr); // write end of stream symbol |
234 | | //sum += 2; |
235 | |
|
236 | 0 | if (verify) |
237 | 0 | { |
238 | 0 | Byte* arr2 = nullptr; |
239 | 0 | size_t numBytes2 = 0; |
240 | 0 | if (!decompress(*arrRLE, numBytesRLE, &arr2, numBytes2) || numBytes2 != numBytes) |
241 | 0 | { |
242 | 0 | delete[] arr2; |
243 | 0 | return false; |
244 | 0 | } |
245 | 0 | int nCheck = memcmp(arr, arr2, numBytes); |
246 | 0 | delete[] arr2; |
247 | 0 | if (nCheck != 0) |
248 | 0 | return false; |
249 | 0 | } |
250 | | |
251 | 0 | return true; |
252 | 0 | } |
253 | | |
254 | | // -------------------------------------------------------------------------- ; |
255 | | |
256 | | bool RLE::decompress(const Byte* arrRLE, size_t nBytesRemainingIn, Byte** arr, size_t& numBytes) |
257 | 0 | { |
258 | 0 | if (!arrRLE || nBytesRemainingIn < 2) |
259 | 0 | return false; |
260 | | |
261 | | // first count the encoded bytes |
262 | 0 | const Byte* srcPtr = arrRLE; |
263 | 0 | size_t nBytesRemaining = nBytesRemainingIn - 2; |
264 | 0 | size_t sum = 0; |
265 | |
|
266 | 0 | short cnt = readCount(&srcPtr); |
267 | 0 | while (cnt != -32768) |
268 | 0 | { |
269 | 0 | sum += cnt < 0 ? -cnt : cnt; |
270 | 0 | size_t n = cnt > 0 ? cnt : 1; |
271 | |
|
272 | 0 | if (nBytesRemaining < n + 2) |
273 | 0 | return false; |
274 | | |
275 | 0 | srcPtr += n; |
276 | 0 | cnt = readCount(&srcPtr); |
277 | |
|
278 | 0 | nBytesRemaining -= n + 2; |
279 | 0 | } |
280 | | |
281 | 0 | numBytes = sum; |
282 | |
|
283 | 0 | if (numBytes == 0) |
284 | 0 | { |
285 | 0 | *arr = nullptr; |
286 | 0 | return false; |
287 | 0 | } |
288 | | |
289 | 0 | *arr = new Byte[numBytes]; |
290 | 0 | if (!*arr) |
291 | 0 | return false; |
292 | | |
293 | 0 | return decompress(arrRLE, nBytesRemainingIn, *arr, numBytes); |
294 | 0 | } |
295 | | |
296 | | // -------------------------------------------------------------------------- ; |
297 | | |
298 | | bool RLE::decompress(const Byte* arrRLE, size_t nBytesRemaining, Byte* arr, size_t arrSize) |
299 | 0 | { |
300 | 0 | if (!arrRLE || !arr || nBytesRemaining < 2) |
301 | 0 | return false; |
302 | | |
303 | 0 | const Byte* srcPtr = arrRLE; |
304 | 0 | size_t arrIdx = 0; |
305 | 0 | nBytesRemaining -= 2; |
306 | |
|
307 | 0 | short cnt = readCount(&srcPtr); |
308 | 0 | while (cnt != -32768) |
309 | 0 | { |
310 | 0 | int i = (cnt <= 0) ? -cnt : cnt; |
311 | 0 | size_t m = (cnt <= 0) ? 1 : (size_t)i; // <= not < to fail gracefully in case of corrupted blob for old version <= 2 which had no checksum |
312 | |
|
313 | 0 | if (nBytesRemaining < m + 2 || arrIdx + i > arrSize) |
314 | 0 | return false; |
315 | | |
316 | 0 | if (cnt > 0) |
317 | 0 | { |
318 | 0 | while (i--) arr[arrIdx++] = *srcPtr++; |
319 | 0 | } |
320 | 0 | else |
321 | 0 | { |
322 | 0 | Byte b = *srcPtr++; |
323 | 0 | while (i--) arr[arrIdx++] = b; |
324 | 0 | } |
325 | |
|
326 | 0 | nBytesRemaining -= m + 2; |
327 | 0 | cnt = readCount(&srcPtr); |
328 | 0 | } |
329 | | |
330 | 0 | return true; |
331 | 0 | } |
332 | | |
333 | | // -------------------------------------------------------------------------- ; |
334 | | |
335 | | void RLE::writeCount(short cnt, Byte** ppCnt, Byte** ppDst) |
336 | 0 | { |
337 | 0 | SWAP_2(cnt); // write short's in little endian byte order, always |
338 | | #ifdef CSA_BUILD |
339 | | (*ppCnt)[0] = static_cast<Byte>(cnt); |
340 | | (*ppCnt)[1] = static_cast<Byte>(cnt >> 8); |
341 | | #else |
342 | 0 | memcpy(*ppCnt, &cnt, sizeof(short)); |
343 | 0 | #endif |
344 | 0 | *ppCnt = *ppDst; |
345 | 0 | *ppDst += 2; |
346 | 0 | } |
347 | | |
348 | | // -------------------------------------------------------------------------- ; |
349 | | |
350 | | short RLE::readCount(const Byte** ppCnt) |
351 | 0 | { |
352 | 0 | short cnt; |
353 | 0 | memcpy(&cnt, *ppCnt, sizeof(short)); |
354 | 0 | SWAP_2(cnt); |
355 | 0 | *ppCnt += 2; |
356 | 0 | return cnt; |
357 | 0 | } |
358 | | |
359 | | // -------------------------------------------------------------------------- ; |
360 | | |