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