1 : /******************************************************************************
2 : * $Id: rmflzw.cpp 11865 2007-08-09 11:53:57Z warmerdam $
3 : *
4 : * Project: Raster Matrix Format
5 : * Purpose: Implementation of the ad-hoc compression algorithm used in
6 : * GIS "Panorama"/"Integratsia".
7 : * Author: Andrey Kiselev, dron@ak4719.spb.edu
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2009, Andrey Kiselev <dron@ak4719.spb.edu>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_conv.h"
32 :
33 : #include "rmfdataset.h"
34 :
35 : /*
36 : * The encoded data stream is a series of records.
37 : *
38 : * Encoded record consist from the 1-byte record header followed by the
39 : * encoded data block. Header specifies the number of elements in the data
40 : * block and encoding type. Header format
41 : *
42 : * +---+---+---+---+---+---+---+---+
43 : * | type | count |
44 : * +---+---+---+---+---+---+---+---+
45 : * 7 6 5 4 3 2 1 0
46 : *
47 : * If count is zero then it means that there are more than 31 elements in this
48 : * record. Read the next byte in the stream and increase its value with 32 to
49 : * get the count. In this case maximum number of elements is 287.
50 : *
51 : * The "type" field specifies encoding type. It can be either difference
52 : * between the previous and the next data value (for the first element the
53 : * previous value is zero) or out-of-range codes.
54 : *
55 : * In case of "out of range" or "zero difference" values there are no more
56 : * elements in record after the header. Otherwise read as much encoded
57 : * elements as count specifies.
58 : */
59 :
60 : // Encoding types
61 : #define TYPE_OUT 0x00 // Value is out of range
62 : #define TYPE_ZERO 0x20 // Zero difference
63 : #define TYPE_INT4 0x40 // Difference is 4-bit wide
64 : #define TYPE_INT8 0x60 // Difference is 8-bit wide
65 : #define TYPE_INT12 0x80 // Difference is 12-bit wide
66 : #define TYPE_INT16 0xA0 // Difference is 16-bit wide
67 : #define TYPE_INT24 0xC0 // Difference is 24-bit wide
68 : #define TYPE_INT32 0xE0 // Difference is 32-bit wide
69 :
70 : // Encoding ranges
71 : #define RANGE_INT4 0x00000007L // 4-bit
72 : #define RANGE_INT12 0x000007FFL // 12-bit
73 : #define RANGE_INT24 0x007FFFFFL // 24-bit
74 :
75 : // Out of range codes
76 : #define OUT_INT4 ((GInt32)0xFFFFFFF8)
77 : #define OUT_INT8 ((GInt32)0xFFFFFF80)
78 : #define OUT_INT12 ((GInt32)0xFFFFF800)
79 : #define OUT_INT16 ((GInt32)0xFFFF8000)
80 : #define OUT_INT24 ((GInt32)0xFF800000)
81 : #define OUT_INT32 ((GInt32)0x80000000)
82 :
83 : // Inversion masks
84 : #define INV_INT4 0xFFFFFFF0L
85 : #define INV_INT12 0xFFFFF000L
86 : #define INV_INT24 0xFF000000L
87 :
88 :
89 : /************************************************************************/
90 : /* DEMDecompress() */
91 : /************************************************************************/
92 :
93 0 : int RMFDataset::DEMDecompress( const GByte* pabyIn, GUInt32 nSizeIn,
94 : GByte* pabyOut, GUInt32 nSizeOut )
95 : {
96 : GUInt32 nCount; // Number of encoded data elements to read
97 : char* pabyTempIn;
98 : GInt32* paiOut;
99 : GInt32 nType; // The encoding type
100 0 : GInt32 iPrev = 0; // The last data value decoded
101 : GInt32 nCode;
102 :
103 0 : if ( pabyIn == 0 ||
104 : pabyOut == 0 ||
105 : nSizeOut < nSizeIn ||
106 : nSizeIn < 2 )
107 0 : return 0;
108 :
109 0 : pabyTempIn = (char*)pabyIn;
110 0 : paiOut = (GInt32*)pabyOut;
111 0 : nSizeOut /= sizeof(GInt32);
112 :
113 0 : while ( nSizeIn > 0 )
114 : {
115 : // Read number of codes in the record and encoding type
116 0 : nCount = *pabyTempIn & 0x1F;
117 0 : nType = *pabyTempIn++ & 0xE0;
118 0 : nSizeIn--;
119 0 : if ( nCount == 0 )
120 : {
121 0 : if ( nSizeIn == 0 )
122 0 : break;
123 0 : nCount = 32 + *((unsigned char*)pabyTempIn++);
124 0 : nSizeIn--;
125 : }
126 :
127 0 : switch (nType)
128 : {
129 : case TYPE_ZERO:
130 0 : if ( nSizeOut < nCount )
131 0 : break;
132 0 : nSizeOut -= nCount;
133 0 : while ( nCount-- > 0 )
134 0 : *paiOut++ = iPrev;
135 0 : break;
136 :
137 : case TYPE_OUT:
138 0 : if ( nSizeOut < nCount )
139 0 : break;
140 0 : nSizeOut -= nCount;
141 0 : while ( nCount-- > 0 )
142 0 : *paiOut++ = OUT_INT32;
143 0 : break;
144 :
145 : case TYPE_INT4:
146 0 : if ( nSizeIn < nCount / 2 )
147 0 : break;
148 0 : if ( nSizeOut < nCount )
149 0 : break;
150 0 : nSizeIn -= nCount / 2;
151 0 : nSizeOut -= nCount;
152 0 : while ( nCount-- > 0 )
153 : {
154 0 : nCode = (*pabyTempIn) & 0x0F;
155 0 : if ( nCode > RANGE_INT4 )
156 0 : nCode |= INV_INT4;
157 : *paiOut++ = ( nCode == OUT_INT4 ) ?
158 0 : OUT_INT32 : iPrev += nCode;
159 :
160 0 : if ( nCount-- == 0 )
161 : {
162 0 : pabyTempIn++;
163 0 : nSizeIn--;
164 0 : break;
165 : }
166 :
167 0 : nCode = ((*pabyTempIn++)>>4) & 0x0F;
168 0 : if ( nCode > RANGE_INT4 )
169 0 : nCode |= INV_INT4;
170 : *paiOut++ = ( nCode == OUT_INT4 ) ?
171 0 : OUT_INT32 : iPrev += nCode;
172 : }
173 0 : break;
174 :
175 : case TYPE_INT8:
176 0 : if ( nSizeIn < nCount )
177 0 : break;
178 0 : if ( nSizeOut < nCount )
179 0 : break;
180 0 : nSizeIn -= nCount;
181 0 : nSizeOut -= nCount;
182 0 : while ( nCount-- > 0 )
183 : {
184 : *paiOut++ = ( (nCode = *pabyTempIn++) == OUT_INT8 ) ?
185 0 : OUT_INT32 : iPrev += nCode;
186 : }
187 0 : break;
188 :
189 : case TYPE_INT12:
190 0 : if ( nSizeIn < 3 * nCount / 2 )
191 0 : break;
192 0 : if ( nSizeOut < nCount )
193 0 : break;
194 0 : nSizeIn -= 3 * nCount / 2;
195 0 : nSizeOut -= nCount;
196 :
197 0 : while ( nCount-- > 0 )
198 : {
199 0 : nCode = *((GInt16*)pabyTempIn++) & 0x0FFF;
200 0 : if ( nCode > RANGE_INT12 )
201 0 : nCode |= INV_INT12;
202 : *paiOut++ = ( nCode == OUT_INT12 ) ?
203 0 : OUT_INT32 : iPrev += nCode;
204 :
205 0 : if ( nCount-- == 0 )
206 : {
207 0 : pabyTempIn++;
208 0 : nSizeIn--;
209 0 : break;
210 : }
211 :
212 0 : nCode = ( (*(GInt16*)pabyTempIn) >> 4 ) & 0x0FFF;
213 0 : pabyTempIn += 2;
214 0 : if ( nCode > RANGE_INT12 )
215 0 : nCode |= INV_INT12;
216 : *paiOut++ = ( nCode == OUT_INT12 ) ?
217 0 : OUT_INT32 : iPrev += nCode;
218 : }
219 0 : break;
220 :
221 : case TYPE_INT16:
222 0 : if ( nSizeIn < 2 * nCount )
223 0 : break;
224 0 : if ( nSizeOut < nCount )
225 0 : break;
226 0 : nSizeIn -= 2 * nCount;
227 0 : nSizeOut -= nCount;
228 :
229 0 : while ( nCount-- > 0 )
230 : {
231 0 : nCode = *((GInt16*)pabyTempIn);
232 0 : pabyTempIn += 2;
233 : *paiOut++ = ( nCode == OUT_INT16 ) ?
234 0 : OUT_INT32 : iPrev += nCode;
235 : }
236 0 : break;
237 :
238 : case TYPE_INT24:
239 0 : if ( nSizeIn < 3 * nCount )
240 0 : break;
241 0 : if ( nSizeOut < nCount )
242 0 : break;
243 0 : nSizeIn -= 3 * nCount;
244 0 : nSizeOut -= nCount;
245 :
246 0 : while ( nCount-- > 0 )
247 : {
248 0 : nCode =*((GInt32 *)pabyTempIn) & 0x0FFF;
249 0 : pabyTempIn += 3;
250 0 : if ( nCode > RANGE_INT24 )
251 0 : nCode |= INV_INT24;
252 : *paiOut++ = ( nCode == OUT_INT24 ) ?
253 0 : OUT_INT32 : iPrev += nCode;
254 : }
255 0 : break;
256 :
257 : case TYPE_INT32:
258 0 : if ( nSizeIn < 4 * nCount )
259 0 : break;
260 0 : if ( nSizeOut < nCount )
261 0 : break;
262 0 : nSizeIn -= 4 * nCount;
263 0 : nSizeOut -= nCount;
264 :
265 0 : while ( nCount-- > 0 )
266 : {
267 0 : nCode = *(GInt32 *)pabyTempIn;
268 0 : pabyTempIn += 4;
269 : *paiOut++ = ( nCode == OUT_INT32 ) ?
270 0 : OUT_INT32 : iPrev += nCode;
271 : }
272 : break;
273 : }
274 : }
275 :
276 0 : return ((GByte*)paiOut - pabyOut);
277 : }
278 :
|