Line data Source code
1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the CPCIDSKVectorSegment class's
4 : * ConsistencyCheck() method.
5 : *
6 : ******************************************************************************
7 : * Copyright (c) 2010
8 : * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "pcidsk_file.h"
30 : #include "pcidsk_exception.h"
31 : #include "core/pcidsk_utils.h"
32 : #include "segment/cpcidskvectorsegment.h"
33 : #include <cstring>
34 : #include <cstdio>
35 :
36 : using namespace PCIDSK;
37 :
38 : /* -------------------------------------------------------------------- */
39 : /* Size of a block in the record/vertex block tables. This is */
40 : /* determined by the PCIDSK format and may not be changed. */
41 : /* -------------------------------------------------------------------- */
42 : static const int block_page_size = 8192;
43 : #ifndef CPL_BASE_H_INCLUDED
44 : template<class T> static void CPL_IGNORE_RET_VAL(T) {}
45 : #endif
46 :
47 : /************************************************************************/
48 : /* ==================================================================== */
49 : /* SpaceMap */
50 : /* */
51 : /* Helper class to track space allocations. */
52 : /* ==================================================================== */
53 : /************************************************************************/
54 :
55 : class SpaceMap
56 : {
57 : public:
58 : std::vector<uint32> offsets;
59 : std::vector<uint32> sizes;
60 :
61 : // binary search for the offset closes to our target or earlier.
62 0 : uint32 FindPreceding( uint32 offset ) const
63 : {
64 0 : if( offsets.empty() )
65 0 : return 0;
66 :
67 0 : uint32 start=0, end=static_cast<uint32>(offsets.size())-1;
68 :
69 0 : while( end > start )
70 : {
71 0 : uint32 middle = (start+end+1) / 2;
72 0 : if( offsets[middle] > offset )
73 0 : end = middle-1;
74 0 : else if( offsets[middle] < offset )
75 0 : start = middle;
76 : else
77 0 : return middle;
78 : }
79 :
80 0 : return start;
81 : }
82 :
83 0 : bool AddChunk( uint32 offset, uint32 size )
84 : {
85 0 : uint32 preceding = FindPreceding( offset );
86 :
87 : // special case for empty
88 0 : if( offsets.empty() )
89 : {
90 0 : offsets.push_back( offset );
91 0 : sizes.push_back( size );
92 0 : return false;
93 : }
94 :
95 : // special case for before first.
96 0 : if( offset < offsets[0] )
97 : {
98 0 : if( offset+size > offsets[0] )
99 0 : return true;
100 :
101 0 : if( offset+size == offsets[0] )
102 : {
103 0 : offsets[0] = offset;
104 0 : sizes[0] += size;
105 : }
106 : else
107 : {
108 0 : offsets.insert( offsets.begin(), offset );
109 0 : sizes.insert( sizes.begin(), size );
110 : }
111 0 : return false;
112 : }
113 :
114 0 : if( offsets[preceding] + sizes[preceding] > offset )
115 : {
116 : // conflict!
117 0 : return true;
118 : }
119 :
120 0 : if( preceding+1 < offsets.size()
121 0 : && offsets[preceding+1] < offset+size )
122 : {
123 : // conflict!
124 0 : return true;
125 : }
126 :
127 : // can we merge into preceding entry?
128 0 : if( offsets[preceding] + sizes[preceding] == offset )
129 : {
130 0 : sizes[preceding] += size;
131 0 : return false;
132 : }
133 :
134 : // can we merge into following entry?
135 0 : if( preceding+1 < offsets.size()
136 0 : && offsets[preceding+1] == offset+size )
137 : {
138 0 : offsets[preceding+1] = offset;
139 0 : sizes[preceding+1] += size;
140 0 : return false;
141 : }
142 :
143 : // Insert after preceding.
144 0 : offsets.insert( offsets.begin() + (preceding + 1), offset );
145 0 : sizes.insert( sizes.begin() + (preceding + 1), size );
146 :
147 0 : return false;
148 : }
149 : };
150 :
151 :
152 :
153 : /************************************************************************/
154 : /* ConsistencyCheck() */
155 : /************************************************************************/
156 :
157 0 : std::string CPCIDSKVectorSegment::ConsistencyCheck()
158 :
159 : {
160 0 : Synchronize();
161 :
162 0 : std::string report = CPCIDSKSegment::ConsistencyCheck();
163 :
164 0 : report += ConsistencyCheck_Header();
165 0 : report += ConsistencyCheck_DataIndices();
166 0 : report += ConsistencyCheck_ShapeIndices();
167 :
168 0 : if( report != "" )
169 0 : fprintf( stderr, "ConsistencyCheck() Report:\n%s", report.c_str() );/*ok*/
170 :
171 0 : return report;
172 : }
173 :
174 : /************************************************************************/
175 : /* ConsistencyCheck_Header() */
176 : /* */
177 : /* Check that the header sections are non-overlapping and fit */
178 : /* in the blocks indicated. */
179 : /* */
180 : /* Verify some "fixed" values. */
181 : /************************************************************************/
182 :
183 0 : std::string CPCIDSKVectorSegment::ConsistencyCheck_Header()
184 :
185 : {
186 0 : std::string report;
187 :
188 0 : LoadHeader();
189 :
190 0 : if( vh.header_blocks < 1 )
191 0 : report += "less than one header_blocks\n";
192 :
193 0 : if( vh.header_blocks * block_page_size > GetContentSize() )
194 0 : report += "header blocks larger than segment size!";
195 :
196 :
197 0 : SpaceMap smap;
198 : int i;
199 :
200 0 : for( i = 0; i < 4; i++ )
201 : {
202 0 : if( smap.AddChunk( vh.section_offsets[i], vh.section_sizes[i] ) )
203 0 : report += "A header section overlaps another header section!\n";
204 :
205 0 : if( vh.section_offsets[i] + vh.section_sizes[i]
206 0 : > vh.header_blocks * block_page_size )
207 0 : report += "A header section goes past end of header.\n";
208 : }
209 :
210 0 : return report;
211 : }
212 :
213 : /************************************************************************/
214 : /* ConsistencyCheck_DataIndices() */
215 : /************************************************************************/
216 :
217 0 : std::string CPCIDSKVectorSegment::ConsistencyCheck_DataIndices()
218 :
219 : {
220 0 : std::string report;
221 :
222 0 : SpaceMap smap;
223 :
224 0 : CPL_IGNORE_RET_VAL(smap.AddChunk( 0, vh.header_blocks ));
225 :
226 0 : for( int section = 0; section < 2; section++ )
227 : {
228 0 : const std::vector<uint32> *map = di[section].GetIndex();
229 : unsigned int i;
230 :
231 0 : for( i = 0; i < map->size(); i++ )
232 : {
233 0 : if( smap.AddChunk( (*map)[i], 1 ) )
234 : {
235 : char msg[100];
236 :
237 0 : snprintf( msg, sizeof(msg),
238 : "Conflict for block %d, held by at least data index '%d'.\n",
239 0 : (*map)[i], section );
240 :
241 0 : report += msg;
242 : }
243 : }
244 :
245 0 : if( di[section].bytes > di[section].block_count * block_page_size )
246 : {
247 0 : report += "bytes for data index to large for block count.\n";
248 : }
249 : }
250 :
251 0 : return report;
252 : }
253 :
254 : /************************************************************************/
255 : /* ConsistencyCheck_ShapeIndices() */
256 : /************************************************************************/
257 :
258 0 : std::string CPCIDSKVectorSegment::ConsistencyCheck_ShapeIndices()
259 :
260 : {
261 0 : std::string report;
262 0 : SpaceMap vmap, rmap;
263 0 : std::map<ShapeId,uint32> id_map;
264 : int iShape;
265 :
266 0 : for( iShape = 0; iShape < total_shape_count; iShape++ )
267 : {
268 0 : AccessShapeByIndex( iShape );
269 :
270 0 : unsigned int toff = iShape - shape_index_start;
271 :
272 0 : if( id_map.count(shape_index_ids[toff]) > 0 )
273 : {
274 : char msg[100];
275 :
276 0 : snprintf( msg, sizeof(msg),
277 : "ShapeID %d is used for shape %u and %u!\n",
278 0 : shape_index_ids[toff],
279 0 : toff, id_map[shape_index_ids[toff]]);
280 0 : report += msg;
281 : }
282 :
283 0 : int32 shape_id = shape_index_ids[toff];
284 0 : if (shape_id == NullShapeId)
285 : {
286 : // ignore deleted shapes
287 0 : continue;
288 : }
289 :
290 0 : id_map[shape_id] = toff;
291 :
292 :
293 0 : if( shape_index_vertex_off[toff] != 0xffffffff )
294 : {
295 : uint32 vertex_count;
296 : uint32 vertex_size;
297 0 : uint32 vert_off = shape_index_vertex_off[toff];
298 :
299 0 : memcpy( &vertex_size, GetData( sec_vert, vert_off, nullptr, 4 ), 4 );
300 0 : memcpy( &vertex_count, GetData( sec_vert, vert_off+4, nullptr, 4 ), 4 );
301 0 : if( needs_swap )
302 : {
303 0 : SwapData( &vertex_count, 4, 1 );
304 0 : SwapData( &vertex_size, 4, 1 );
305 : }
306 :
307 0 : if( vertex_size < vertex_count * 24 + 8 )
308 : {
309 0 : report += "vertices for shape index seem larger than space allocated.\n";
310 : }
311 :
312 0 : if( vert_off + vertex_size > di[sec_vert].GetSectionEnd() )
313 : {
314 0 : report += "record overruns data index bytes.\n";
315 : }
316 :
317 0 : if( vmap.AddChunk( vert_off, vertex_size ) )
318 : {
319 0 : report += "vertex overlap detected!\n";
320 : }
321 : }
322 :
323 0 : if( shape_index_record_off[toff] != 0xffffffff )
324 : {
325 0 : uint32 rec_off = shape_index_record_off[toff];
326 0 : uint32 offset = rec_off;
327 : uint32 record_size, i;
328 0 : ShapeField wfld;
329 :
330 0 : memcpy( &record_size, GetData( sec_record, rec_off, nullptr, 4 ), 4 );
331 0 : if( needs_swap )
332 0 : SwapData( &record_size, 4, 1 );
333 :
334 0 : offset += 4;
335 0 : for( i = 0; i < vh.field_names.size(); i++ )
336 0 : offset = ReadField( offset, wfld, vh.field_types[i],
337 : sec_record );
338 :
339 0 : if( offset - rec_off > record_size )
340 0 : report += "record actually larger than declared record size.\n";
341 :
342 0 : if( rec_off + record_size > di[sec_record].GetSectionEnd() )
343 : {
344 0 : report += "record overruns data index bytes.\n";
345 : }
346 :
347 0 : if( rmap.AddChunk( rec_off, record_size ) )
348 : {
349 0 : report += "record overlap detected!\n";
350 : }
351 : }
352 : }
353 :
354 0 : return report;
355 : }
|