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 <cstring>
25 #include "BitStuffer.h"
26 
27 using namespace std;
28 using namespace LercNS;
29 
30 // -------------------------------------------------------------------------- ;
31 
read(Byte ** ppByte,vector<unsigned int> & dataVec) const32 bool BitStuffer::read(Byte** ppByte, vector<unsigned int>& dataVec) const
33 {
34   if (!ppByte)
35     return false;
36 
37   Byte numBitsByte = **ppByte;
38   (*ppByte)++;
39 
40   int bits67 = numBitsByte >> 6;
41   int n = (bits67 == 0) ? 4 : 3 - bits67;
42 
43   numBitsByte &= 63;    // bits 0-5;
44 
45   unsigned int numElements = 0;
46   if (!readUInt(ppByte, numElements, n))
47     return false;
48 
49   if (numBitsByte >= 32)
50     return false;
51 
52   int numBits = numBitsByte;
53   unsigned int numUInts = (numElements * numBits + 31) / 32;
54   dataVec.resize(numElements, 0);    // init with 0
55 
56   if (numUInts > 0)    // numBits can be 0
57   {
58     m_tmpBitStuffVec.resize(numUInts);
59     m_tmpBitStuffVec[numUInts - 1] = 0;    // set last uint to 0
60 
61     unsigned int nBytesToCopy = (numElements * numBits + 7) / 8;
62     memcpy(&m_tmpBitStuffVec[0], *ppByte, nBytesToCopy);
63 
64     unsigned int* arr = &m_tmpBitStuffVec[0];
65     unsigned int* srcPtr = arr;
66     for (unsigned int i = 0; i < numUInts; i++)
67     {
68       SWAP_4(*srcPtr);
69       srcPtr++;
70     }
71 
72     unsigned int* pLastULong = &m_tmpBitStuffVec[numUInts - 1];
73     unsigned int n = numTailBytesNotNeeded(numElements, numBits);
74     while (n--)
75       *pLastULong <<= 8;
76 
77     // do the un-stuffing
78     srcPtr = arr;
79     unsigned int* dstPtr = &dataVec[0];
80     int bitPos = 0;
81 
82     for (unsigned int i = 0; i < numElements; i++)
83     {
84       if (32 - bitPos >= numBits)
85       {
86         unsigned int val;
87         memcpy(&val, srcPtr, sizeof(unsigned int));
88         unsigned int n = val << bitPos;
89         *dstPtr++ = n >> (32 - numBits);
90 
91         bitPos += numBits;
92         if (bitPos == 32)    // shift >= 32 is undefined
93         {
94           bitPos = 0;
95           srcPtr++;
96         }
97       }
98       else
99       {
100         unsigned int val;
101         memcpy(&val, srcPtr, sizeof(unsigned int));
102         srcPtr++;
103         unsigned int n = val << bitPos;
104         *dstPtr = n >> (32 - numBits);
105         bitPos -= (32 - numBits);
106         memcpy(&val, srcPtr, sizeof(unsigned int));
107         *dstPtr++ |= val >> (32 - bitPos);
108       }
109     }
110 
111     *ppByte += nBytesToCopy;
112   }
113 
114   return true;
115 }
116 
117 // -------------------------------------------------------------------------- ;
118 // -------------------------------------------------------------------------- ;
119 
readUInt(Byte ** ppByte,unsigned int & k,int numBytes)120 bool BitStuffer::readUInt(Byte** ppByte, unsigned int& k, int numBytes)
121 {
122   Byte* ptr = *ppByte;
123 
124   if (numBytes == 1)
125   {
126     k = *ptr;
127   }
128   else if (numBytes == 2)
129   {
130     unsigned short s;
131     memcpy(&s, ptr, sizeof(unsigned short));
132     SWAP_2(s);
133     k = s;
134   }
135   else if (numBytes == 4)
136   {
137     memcpy(&k, ptr, sizeof(unsigned int));
138     SWAP_4(k);
139   }
140   else
141     return false;
142 
143   *ppByte = ptr + numBytes;
144   return true;
145 }
146 
147 // -------------------------------------------------------------------------- ;
148 
numTailBytesNotNeeded(unsigned int numElem,int numBits)149 unsigned int BitStuffer::numTailBytesNotNeeded(unsigned int numElem, int numBits)
150 {
151   int numBitsTail = (numElem * numBits) & 31;
152   int numBytesTail = (numBitsTail + 7) >> 3;
153   return (numBytesTail > 0) ? 4 - numBytesTail : 0;
154 }
155 
156 // -------------------------------------------------------------------------- ;
157 
158