/src/gdal/third_party/LercLib/BitStuffer2.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 <algorithm> |
25 | | #include <cassert> |
26 | | #include "Defines.h" |
27 | | #include "BitStuffer2.h" |
28 | | |
29 | | using namespace std; |
30 | | USING_NAMESPACE_LERC |
31 | | |
32 | | // -------------------------------------------------------------------------- ; |
33 | | |
34 | | // if you change Encode(...) / Decode(...), don't forget to update ComputeNumBytesNeeded(...) |
35 | | |
36 | | bool BitStuffer2::EncodeSimple(Byte** ppByte, const vector<unsigned int>& dataVec, int lerc2Version) const |
37 | 0 | { |
38 | 0 | if (!ppByte || dataVec.empty()) |
39 | 0 | return false; |
40 | | |
41 | 0 | unsigned int maxElem = *max_element(dataVec.begin(), dataVec.end()); |
42 | 0 | int numBits = 0; |
43 | 0 | while ((numBits < 32) && (maxElem >> numBits)) |
44 | 0 | numBits++; |
45 | |
|
46 | 0 | if (numBits >= 32) |
47 | 0 | return false; |
48 | | |
49 | 0 | Byte numBitsByte = (Byte)numBits; |
50 | 0 | unsigned int numElements = (unsigned int)dataVec.size(); |
51 | 0 | unsigned int numUInts = (numElements * numBits + 31) / 32; |
52 | | |
53 | | // use the upper 2 bits to encode the type used for numElements: Byte, ushort, or uint |
54 | 0 | int n = NumBytesUInt(numElements); |
55 | 0 | int bits67 = (n == 4) ? 0 : 3 - n; |
56 | 0 | numBitsByte |= bits67 << 6; |
57 | | |
58 | | // bit5 = 0 means simple mode |
59 | |
|
60 | 0 | **ppByte = numBitsByte; |
61 | 0 | (*ppByte)++; |
62 | |
|
63 | 0 | if (!EncodeUInt(ppByte, numElements, n)) |
64 | 0 | return false; |
65 | | |
66 | 0 | if (numUInts > 0) // numBits can be 0, then we only write the header |
67 | 0 | { |
68 | 0 | if (lerc2Version >= 3) |
69 | 0 | BitStuff(ppByte, dataVec, numBits); |
70 | 0 | else |
71 | 0 | BitStuff_Before_Lerc2v3(ppByte, dataVec, numBits); |
72 | 0 | } |
73 | |
|
74 | 0 | return true; |
75 | 0 | } |
76 | | |
77 | | // -------------------------------------------------------------------------- ; |
78 | | |
79 | | bool BitStuffer2::EncodeLut(Byte** ppByte, const vector<pair<unsigned int, unsigned int> >& sortedDataVec, int lerc2Version) const |
80 | 0 | { |
81 | 0 | if (!ppByte || sortedDataVec.empty()) |
82 | 0 | return false; |
83 | | |
84 | 0 | if (sortedDataVec[0].first != 0) // corresponds to min |
85 | 0 | return false; |
86 | | |
87 | | // collect the different values for the lut |
88 | 0 | unsigned int numElem = (unsigned int)sortedDataVec.size(); |
89 | 0 | unsigned int indexLut = 0; |
90 | |
|
91 | 0 | m_tmpLutVec.resize(0); // omit the 0 throughout that corresponds to min |
92 | 0 | m_tmpIndexVec.assign(numElem, 0); |
93 | |
|
94 | 0 | for (unsigned int i = 1; i < numElem; i++) |
95 | 0 | { |
96 | 0 | unsigned int prev = sortedDataVec[i - 1].first; |
97 | 0 | m_tmpIndexVec[sortedDataVec[i - 1].second] = indexLut; |
98 | |
|
99 | 0 | if (sortedDataVec[i].first != prev) |
100 | 0 | { |
101 | 0 | m_tmpLutVec.push_back(sortedDataVec[i].first); |
102 | 0 | indexLut++; |
103 | 0 | } |
104 | 0 | } |
105 | 0 | m_tmpIndexVec[sortedDataVec[numElem - 1].second] = indexLut; // don't forget the last one |
106 | | |
107 | | // write first 2 data elements same as simple, but bit5 set to 1 |
108 | 0 | unsigned int maxElem = m_tmpLutVec.back(); |
109 | 0 | int numBits = 0; |
110 | 0 | while ((numBits < 32) && (maxElem >> numBits)) |
111 | 0 | numBits++; |
112 | |
|
113 | 0 | if (numBits >= 32) |
114 | 0 | return false; |
115 | | |
116 | 0 | Byte numBitsByte = (Byte)numBits; |
117 | | |
118 | | // use the upper 2 bits to encode the type used for numElem: byte, ushort, or uint |
119 | 0 | int n = NumBytesUInt(numElem); |
120 | 0 | int bits67 = (n == 4) ? 0 : 3 - n; |
121 | 0 | numBitsByte |= bits67 << 6; |
122 | |
|
123 | 0 | numBitsByte |= (1 << 5); // bit 5 = 1 means lut mode |
124 | |
|
125 | 0 | **ppByte = numBitsByte; |
126 | 0 | (*ppByte)++; |
127 | |
|
128 | 0 | if (!EncodeUInt(ppByte, numElem, n)) // numElements = numIndexes to lut |
129 | 0 | return false; |
130 | | |
131 | 0 | unsigned int nLut = (unsigned int)m_tmpLutVec.size(); |
132 | 0 | if (nLut < 1 || nLut >= 255) |
133 | 0 | return false; |
134 | | |
135 | 0 | **ppByte = (Byte)nLut + 1; // size of lut, incl the 0 |
136 | 0 | (*ppByte)++; |
137 | |
|
138 | 0 | if (lerc2Version >= 3) |
139 | 0 | BitStuff(ppByte, m_tmpLutVec, numBits); // lut |
140 | 0 | else |
141 | 0 | BitStuff_Before_Lerc2v3(ppByte, m_tmpLutVec, numBits); |
142 | |
|
143 | 0 | int nBitsLut = 0; |
144 | 0 | while (nLut >> nBitsLut) // indexes are in [0 .. nLut] |
145 | 0 | nBitsLut++; |
146 | |
|
147 | 0 | if (lerc2Version >= 3) |
148 | 0 | BitStuff(ppByte, m_tmpIndexVec, nBitsLut); // indexes |
149 | 0 | else |
150 | 0 | BitStuff_Before_Lerc2v3(ppByte, m_tmpIndexVec, nBitsLut); |
151 | |
|
152 | 0 | return true; |
153 | 0 | } |
154 | | |
155 | | // -------------------------------------------------------------------------- ; |
156 | | |
157 | | // if you change Encode(...) / Decode(...), don't forget to update ComputeNumBytesNeeded(...) |
158 | | |
159 | | bool BitStuffer2::Decode(const Byte** ppByte, size_t& nBytesRemaining, vector<unsigned int>& dataVec, size_t maxElementCount, int lerc2Version) const |
160 | 0 | { |
161 | 0 | if (!ppByte || nBytesRemaining < 1) |
162 | 0 | return false; |
163 | | |
164 | 0 | Byte numBitsByte = **ppByte; |
165 | 0 | (*ppByte)++; |
166 | 0 | nBytesRemaining--; |
167 | |
|
168 | 0 | int bits67 = numBitsByte >> 6; |
169 | 0 | int nb = (bits67 == 0) ? 4 : 3 - bits67; |
170 | |
|
171 | 0 | bool doLut = (numBitsByte & (1 << 5)) ? true : false; // bit 5 |
172 | 0 | numBitsByte &= 31; // bits 0-4; |
173 | 0 | int numBits = numBitsByte; |
174 | |
|
175 | 0 | unsigned int numElements = 0; |
176 | 0 | if (!DecodeUInt(ppByte, nBytesRemaining, numElements, nb)) |
177 | 0 | return false; |
178 | 0 | if (numElements > maxElementCount) |
179 | 0 | return false; |
180 | | |
181 | 0 | if (!doLut) |
182 | 0 | { |
183 | 0 | if (numBits > 0) // numBits can be 0 |
184 | 0 | { |
185 | 0 | if (lerc2Version >= 3) |
186 | 0 | { |
187 | 0 | if (!BitUnStuff(ppByte, nBytesRemaining, dataVec, numElements, numBits)) |
188 | 0 | return false; |
189 | 0 | } |
190 | 0 | else |
191 | 0 | { |
192 | 0 | if (!BitUnStuff_Before_Lerc2v3(ppByte, nBytesRemaining, dataVec, numElements, numBits)) |
193 | 0 | return false; |
194 | 0 | } |
195 | 0 | } |
196 | 0 | } |
197 | 0 | else |
198 | 0 | { |
199 | 0 | if (numBits == 0) // fail gracefully in case of corrupted blob for old version <= 2 which had no checksum |
200 | 0 | return false; |
201 | 0 | if (nBytesRemaining < 1) |
202 | 0 | return false; |
203 | | |
204 | 0 | Byte nLutByte = **ppByte; |
205 | 0 | (*ppByte)++; |
206 | 0 | nBytesRemaining--; |
207 | |
|
208 | 0 | int nLut = nLutByte - 1; |
209 | | |
210 | | // unstuff lut w/o the 0 |
211 | 0 | if (lerc2Version >= 3) |
212 | 0 | { |
213 | 0 | if (!BitUnStuff(ppByte, nBytesRemaining, m_tmpLutVec, nLut, numBits)) |
214 | 0 | return false; |
215 | 0 | } |
216 | 0 | else |
217 | 0 | { |
218 | 0 | if (!BitUnStuff_Before_Lerc2v3(ppByte, nBytesRemaining, m_tmpLutVec, nLut, numBits)) |
219 | 0 | return false; |
220 | 0 | } |
221 | | |
222 | 0 | int nBitsLut = 0; |
223 | 0 | while (nLut >> nBitsLut) |
224 | 0 | nBitsLut++; |
225 | 0 | if (nBitsLut == 0) |
226 | 0 | return false; |
227 | | |
228 | 0 | if (lerc2Version >= 3) |
229 | 0 | { |
230 | | // unstuff indexes |
231 | 0 | if (!BitUnStuff(ppByte, nBytesRemaining, dataVec, numElements, nBitsLut)) |
232 | 0 | return false; |
233 | | |
234 | | // replace indexes by values |
235 | 0 | #if defined(__GNUC__) |
236 | 0 | #pragma GCC diagnostic push |
237 | 0 | #pragma GCC diagnostic ignored "-Wnull-dereference" |
238 | 0 | #endif |
239 | 0 | m_tmpLutVec.insert(m_tmpLutVec.begin(), 0); // put back in the 0 |
240 | 0 | #if defined(__GNUC__) |
241 | 0 | #pragma GCC diagnostic pop |
242 | 0 | #endif |
243 | 0 | for (unsigned int i = 0; i < numElements; i++) |
244 | 0 | { |
245 | 0 | #ifdef GDAL_COMPILATION |
246 | 0 | if (dataVec[i] >= m_tmpLutVec.size()) |
247 | 0 | return false; |
248 | 0 | #endif |
249 | 0 | dataVec[i] = m_tmpLutVec[dataVec[i]]; |
250 | 0 | } |
251 | 0 | } |
252 | 0 | else |
253 | 0 | { |
254 | | // unstuff indexes |
255 | 0 | if (!BitUnStuff_Before_Lerc2v3(ppByte, nBytesRemaining, dataVec, numElements, nBitsLut)) |
256 | 0 | return false; |
257 | | |
258 | | // replace indexes by values |
259 | 0 | #if defined(__GNUC__) |
260 | 0 | #pragma GCC diagnostic push |
261 | 0 | #pragma GCC diagnostic ignored "-Wnull-dereference" |
262 | 0 | #endif |
263 | 0 | m_tmpLutVec.insert(m_tmpLutVec.begin(), 0); // put back in the 0 |
264 | 0 | #if defined(__GNUC__) |
265 | 0 | #pragma GCC diagnostic pop |
266 | 0 | #endif |
267 | 0 | for (unsigned int i = 0; i < numElements; i++) |
268 | 0 | { |
269 | 0 | if (dataVec[i] >= m_tmpLutVec.size()) |
270 | 0 | return false; |
271 | | |
272 | 0 | dataVec[i] = m_tmpLutVec[dataVec[i]]; |
273 | 0 | } |
274 | 0 | } |
275 | 0 | } |
276 | | |
277 | 0 | return true; |
278 | 0 | } |
279 | | |
280 | | // -------------------------------------------------------------------------- ; |
281 | | |
282 | | unsigned int BitStuffer2::ComputeNumBytesNeededLut(const vector<pair<unsigned int, unsigned int> >& sortedDataVec, bool& doLut) |
283 | 0 | { |
284 | 0 | unsigned int maxElem = sortedDataVec.back().first; |
285 | 0 | unsigned int numElem = (unsigned int)sortedDataVec.size(); |
286 | |
|
287 | 0 | int numBits = 0; |
288 | 0 | while ((numBits < 32) && (maxElem >> numBits)) |
289 | 0 | numBits++; |
290 | 0 | unsigned int numBytes = 1 + NumBytesUInt(numElem) + ((numElem * numBits + 7) >> 3); |
291 | | |
292 | | // go through and count how often the value changes |
293 | 0 | int nLut = 0; |
294 | 0 | for (unsigned int i = 1; i < numElem; i++) |
295 | 0 | if (sortedDataVec[i].first != sortedDataVec[i - 1].first) |
296 | 0 | nLut++; |
297 | |
|
298 | 0 | int nBitsLut = 0; |
299 | 0 | while (nLut >> nBitsLut) |
300 | 0 | nBitsLut++; |
301 | |
|
302 | 0 | unsigned int numBitsTotalLut = nLut * numBits; // num bits w/o the 0 |
303 | 0 | unsigned int numBytesLut = 1 + NumBytesUInt(numElem) + 1 + ((numBitsTotalLut + 7) >> 3) + ((numElem * nBitsLut + 7) >> 3); |
304 | |
|
305 | 0 | doLut = numBytesLut < numBytes; |
306 | 0 | return min(numBytesLut, numBytes); |
307 | 0 | } |
308 | | |
309 | | // -------------------------------------------------------------------------- ; |
310 | | // -------------------------------------------------------------------------- ; |
311 | | |
312 | | void BitStuffer2::BitStuff_Before_Lerc2v3(Byte** ppByte, const vector<unsigned int>& dataVec, int numBits) |
313 | 0 | { |
314 | 0 | unsigned int numElements = (unsigned int)dataVec.size(); |
315 | 0 | unsigned int numUInts = (numElements * numBits + 31) / 32; |
316 | 0 | unsigned int numBytes = numUInts * sizeof(unsigned int); |
317 | 0 | unsigned int* arr = (unsigned int*)(*ppByte); |
318 | |
|
319 | 0 | memset(arr, 0, numBytes); |
320 | | |
321 | | // do the stuffing |
322 | 0 | const unsigned int* srcPtr = &dataVec[0]; |
323 | 0 | unsigned int* dstPtr = arr; |
324 | 0 | int bitPos = 0; |
325 | |
|
326 | 0 | for (unsigned int i = 0; i < numElements; i++) |
327 | 0 | { |
328 | 0 | if (32 - bitPos >= numBits) |
329 | 0 | { |
330 | 0 | unsigned int dstValue; |
331 | 0 | memcpy(&dstValue, dstPtr, sizeof(unsigned int)); |
332 | 0 | dstValue |= (*srcPtr++) << (32 - bitPos - numBits); |
333 | 0 | memcpy(dstPtr, &dstValue, sizeof(unsigned int)); |
334 | 0 | bitPos += numBits; |
335 | 0 | if (bitPos == 32) // shift >= 32 is undefined |
336 | 0 | { |
337 | 0 | bitPos = 0; |
338 | 0 | dstPtr++; |
339 | 0 | } |
340 | 0 | } |
341 | 0 | else |
342 | 0 | { |
343 | 0 | unsigned int dstValue; |
344 | 0 | int n = numBits - (32 - bitPos); |
345 | 0 | memcpy(&dstValue, dstPtr, sizeof(unsigned int)); |
346 | 0 | dstValue |= (*srcPtr) >> n; |
347 | 0 | memcpy(dstPtr, &dstValue, sizeof(unsigned int)); |
348 | 0 | dstPtr++; |
349 | 0 | memcpy(&dstValue, dstPtr, sizeof(unsigned int)); |
350 | 0 | dstValue |= (*srcPtr++) << (32 - n); |
351 | 0 | memcpy(dstPtr, &dstValue, sizeof(unsigned int)); |
352 | 0 | bitPos = n; |
353 | 0 | } |
354 | 0 | } |
355 | | |
356 | | // save the 0-3 bytes not used in the last UInt |
357 | 0 | unsigned int numBytesNotNeeded = NumTailBytesNotNeeded(numElements, numBits); |
358 | 0 | unsigned int n = numBytesNotNeeded; |
359 | 0 | for (; n; --n) |
360 | 0 | { |
361 | 0 | unsigned int dstValue; |
362 | 0 | memcpy(&dstValue, dstPtr, sizeof(unsigned int)); |
363 | 0 | dstValue >>= 8; |
364 | 0 | memcpy(dstPtr, &dstValue, sizeof(unsigned int)); |
365 | 0 | } |
366 | |
|
367 | 0 | *ppByte += numBytes - numBytesNotNeeded; |
368 | 0 | } |
369 | | |
370 | | // -------------------------------------------------------------------------- ; |
371 | | |
372 | | bool BitStuffer2::BitUnStuff_Before_Lerc2v3(const Byte** ppByte, size_t& nBytesRemaining, |
373 | | vector<unsigned int>& dataVec, unsigned int numElements, int numBits) const |
374 | 0 | { |
375 | 0 | if (numElements == 0 || numBits >= 32) |
376 | 0 | return false; |
377 | 0 | unsigned long long numUIntsLL = ((unsigned long long)numElements * numBits + 31) / 32; |
378 | 0 | unsigned long long numBytesLL = numUIntsLL * sizeof(unsigned int); |
379 | 0 | size_t numBytes = (size_t)numBytesLL; // could theoretically overflow on 32 bit system |
380 | 0 | size_t numUInts = (size_t)numUIntsLL; |
381 | 0 | unsigned int ntbnn = NumTailBytesNotNeeded(numElements, numBits); |
382 | 0 | if (numBytes != numBytesLL || nBytesRemaining + ntbnn < numBytes) |
383 | 0 | return false; |
384 | | |
385 | 0 | try |
386 | 0 | { |
387 | 0 | dataVec.resize(numElements, 0); // init with 0 |
388 | 0 | m_tmpBitStuffVec.resize(numUInts); |
389 | 0 | } |
390 | 0 | catch( const std::exception& ) |
391 | 0 | { |
392 | 0 | return false; |
393 | 0 | } |
394 | | |
395 | 0 | m_tmpBitStuffVec[numUInts - 1] = 0; // set last uint to 0 |
396 | |
|
397 | 0 | unsigned int nBytesToCopy = (numElements * numBits + 7) / 8; |
398 | 0 | memcpy(&m_tmpBitStuffVec[0], *ppByte, nBytesToCopy); |
399 | |
|
400 | 0 | unsigned int* pLastULong = &m_tmpBitStuffVec[numUInts - 1]; |
401 | 0 | while (ntbnn) |
402 | 0 | { |
403 | 0 | -- ntbnn; |
404 | 0 | *pLastULong <<= 8; |
405 | 0 | } |
406 | |
|
407 | 0 | unsigned int* srcPtr = &m_tmpBitStuffVec[0]; |
408 | 0 | unsigned int* dstPtr = &dataVec[0]; |
409 | 0 | int bitPos = 0; |
410 | |
|
411 | 0 | for (unsigned int i = 0; i < numElements; i++) |
412 | 0 | { |
413 | 0 | if (32 - bitPos >= numBits) |
414 | 0 | { |
415 | 0 | unsigned int val; |
416 | 0 | memcpy(&val, srcPtr, sizeof(unsigned int)); |
417 | 0 | unsigned int n = val << bitPos; |
418 | 0 | *dstPtr++ = n >> (32 - numBits); |
419 | 0 | bitPos += numBits; |
420 | |
|
421 | 0 | if (bitPos == 32) // shift >= 32 is undefined |
422 | 0 | { |
423 | 0 | bitPos = 0; |
424 | 0 | srcPtr++; |
425 | 0 | } |
426 | 0 | } |
427 | 0 | else |
428 | 0 | { |
429 | 0 | unsigned int val; |
430 | 0 | memcpy(&val, srcPtr, sizeof(unsigned int)); |
431 | 0 | srcPtr++; |
432 | 0 | unsigned int n = val << bitPos; |
433 | 0 | *dstPtr = n >> (32 - numBits); |
434 | 0 | bitPos -= (32 - numBits); |
435 | 0 | memcpy(&val, srcPtr, sizeof(unsigned int)); |
436 | 0 | *dstPtr++ |= val >> (32 - bitPos); |
437 | 0 | } |
438 | 0 | } |
439 | |
|
440 | 0 | *ppByte += nBytesToCopy; |
441 | 0 | nBytesRemaining -= nBytesToCopy; |
442 | |
|
443 | 0 | return true; |
444 | 0 | } |
445 | | |
446 | | // -------------------------------------------------------------------------- ; |
447 | | |
448 | | // starting with version Lerc2v3: integer >> into local uint buffer, plus final memcpy |
449 | | |
450 | | void BitStuffer2::BitStuff(Byte** ppByte, const vector<unsigned int>& dataVec, int numBits) const |
451 | 0 | { |
452 | 0 | unsigned int numElements = (unsigned int)dataVec.size(); |
453 | 0 | unsigned int numUInts = (numElements * numBits + 31) / 32; |
454 | 0 | unsigned int numBytes = numUInts * sizeof(unsigned int); |
455 | |
|
456 | 0 | m_tmpBitStuffVec.resize(numUInts); |
457 | 0 | unsigned int* dstPtr = &m_tmpBitStuffVec[0]; |
458 | |
|
459 | 0 | memset(dstPtr, 0, numBytes); |
460 | | |
461 | | // do the stuffing |
462 | 0 | const unsigned int* srcPtr = &dataVec[0]; |
463 | 0 | int bitPos = 0; |
464 | 0 | assert(numBits <= 32); // to avoid coverity warning about large shift a bit later, when doing (*srcPtr++) >> (32 - bitPos) |
465 | | |
466 | 0 | for (unsigned int i = 0; i < numElements; i++) |
467 | 0 | { |
468 | 0 | if (32 - bitPos >= numBits) |
469 | 0 | { |
470 | 0 | *dstPtr |= (*srcPtr++) << bitPos; |
471 | 0 | bitPos += numBits; |
472 | 0 | if (bitPos == 32) // shift >= 32 is undefined |
473 | 0 | { |
474 | 0 | dstPtr++; |
475 | 0 | bitPos = 0; |
476 | 0 | } |
477 | 0 | } |
478 | 0 | else |
479 | 0 | { |
480 | 0 | *dstPtr++ |= (*srcPtr) << bitPos; |
481 | 0 | *dstPtr |= (*srcPtr++) >> (32 - bitPos); |
482 | 0 | bitPos += numBits - 32; |
483 | 0 | } |
484 | 0 | } |
485 | | |
486 | | // copy the bytes to the outgoing byte stream |
487 | 0 | size_t numBytesUsed = numBytes - NumTailBytesNotNeeded(numElements, numBits); |
488 | | #ifdef CSA_BUILD |
489 | | assert( numElements ); |
490 | | #endif |
491 | 0 | memcpy(*ppByte, m_tmpBitStuffVec.data(), numBytesUsed); |
492 | |
|
493 | 0 | *ppByte += numBytesUsed; |
494 | 0 | } |
495 | | |
496 | | // -------------------------------------------------------------------------- ; |
497 | | |
498 | | bool BitStuffer2::BitUnStuff(const Byte** ppByte, size_t& nBytesRemaining, vector<unsigned int>& dataVec, |
499 | | unsigned int numElements, int numBits) const |
500 | 0 | { |
501 | 0 | if (numElements == 0 || numBits >= 32) |
502 | 0 | return false; |
503 | 0 | unsigned long long numUIntsLL = ((unsigned long long)numElements * numBits + 31) / 32; |
504 | 0 | unsigned long long numBytesLL = numUIntsLL * sizeof(unsigned int); |
505 | 0 | size_t numBytes = (size_t)numBytesLL; // could theoretically overflow on 32 bit system |
506 | 0 | if (numBytes != numBytesLL) |
507 | 0 | return false; |
508 | 0 | size_t numUInts = (size_t)numUIntsLL; |
509 | | |
510 | | // copy the bytes from the incoming byte stream |
511 | 0 | const size_t numBytesUsed = numBytes - NumTailBytesNotNeeded(numElements, numBits); |
512 | |
|
513 | 0 | if (nBytesRemaining < numBytesUsed) |
514 | 0 | return false; |
515 | | |
516 | 0 | try |
517 | 0 | { |
518 | 0 | dataVec.resize(numElements); |
519 | 0 | } |
520 | 0 | catch( const std::exception& ) |
521 | 0 | { |
522 | 0 | return false; |
523 | 0 | } |
524 | | |
525 | 0 | try |
526 | 0 | { |
527 | 0 | m_tmpBitStuffVec.resize(numUInts); |
528 | 0 | } |
529 | 0 | catch( const std::exception& ) |
530 | 0 | { |
531 | 0 | return false; |
532 | 0 | } |
533 | | |
534 | 0 | m_tmpBitStuffVec[numUInts - 1] = 0; // set last uint to 0 |
535 | |
|
536 | 0 | memcpy(&m_tmpBitStuffVec[0], *ppByte, numBytesUsed); |
537 | | |
538 | | // do the un-stuffing |
539 | 0 | unsigned int* srcPtr = &m_tmpBitStuffVec[0]; |
540 | 0 | unsigned int* dstPtr = &dataVec[0]; |
541 | 0 | int bitPos = 0; |
542 | 0 | int nb = 32 - numBits; |
543 | |
|
544 | 0 | for (unsigned int i = 0; i < numElements; i++) |
545 | 0 | { |
546 | 0 | if (nb - bitPos >= 0) |
547 | 0 | { |
548 | 0 | *dstPtr++ = ((*srcPtr) << (nb - bitPos)) >> nb; |
549 | 0 | bitPos += numBits; |
550 | 0 | if (bitPos == 32) // shift >= 32 is undefined |
551 | 0 | { |
552 | 0 | srcPtr++; |
553 | 0 | bitPos = 0; |
554 | 0 | } |
555 | 0 | } |
556 | 0 | else |
557 | 0 | { |
558 | 0 | *dstPtr = (*srcPtr++) >> bitPos; |
559 | 0 | *dstPtr++ |= ((*srcPtr) << (64 - numBits - bitPos)) >> nb; |
560 | 0 | bitPos -= nb; |
561 | 0 | } |
562 | 0 | } |
563 | |
|
564 | 0 | *ppByte += numBytesUsed; |
565 | 0 | nBytesRemaining -= numBytesUsed; |
566 | 0 | return true; |
567 | 0 | } |
568 | | |
569 | | // -------------------------------------------------------------------------- ; |
570 | | |