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