/src/gdal/frmts/pcidsk/sdk/segment/cpcidskvectorsegment.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Purpose: Implementation of the CPCIDSKVectorSegment class. |
4 | | * |
5 | | ****************************************************************************** |
6 | | * Copyright (c) 2009 |
7 | | * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada. |
8 | | * |
9 | | * SPDX-License-Identifier: MIT |
10 | | ****************************************************************************/ |
11 | | |
12 | | #include "pcidsk_file.h" |
13 | | #include "pcidsk_exception.h" |
14 | | #include "core/pcidsk_utils.h" |
15 | | #include "segment/cpcidskvectorsegment.h" |
16 | | #include <cassert> |
17 | | #include <cstring> |
18 | | #include <cstdio> |
19 | | #include <algorithm> |
20 | | #include <limits> |
21 | | |
22 | | using namespace PCIDSK; |
23 | | |
24 | | /* -------------------------------------------------------------------- */ |
25 | | /* Size of one page of loaded shapeids. This is not related to */ |
26 | | /* the file format, and may be changed to alter the number of */ |
27 | | /* shapeid pointers kept in RAM at one time from the shape */ |
28 | | /* index. */ |
29 | | /* -------------------------------------------------------------------- */ |
30 | | static const int shapeid_page_size = 1024; |
31 | | |
32 | 4.84k | PCIDSKVectorSegment::~PCIDSKVectorSegment() = default; |
33 | | |
34 | | /************************************************************************/ |
35 | | /* CPCIDSKVectorSegment() */ |
36 | | /************************************************************************/ |
37 | | |
38 | | CPCIDSKVectorSegment::CPCIDSKVectorSegment( PCIDSKFile *fileIn, int segmentIn, |
39 | | const char *segment_pointer ) |
40 | 4.84k | : CPCIDSKSegment( fileIn, segmentIn, segment_pointer ) |
41 | | |
42 | 4.84k | { |
43 | 4.84k | base_initialized = false; |
44 | 4.84k | needs_swap = false; |
45 | | |
46 | 4.84k | total_shape_count = 0; |
47 | 4.84k | valid_shape_count = 0; |
48 | | |
49 | 4.84k | last_shapes_id = NullShapeId; |
50 | 4.84k | last_shapes_index = -1; |
51 | | |
52 | 4.84k | raw_loaded_data_offset = 0; |
53 | 4.84k | vert_loaded_data_offset = 0; |
54 | 4.84k | record_loaded_data_offset = 0; |
55 | 4.84k | raw_loaded_data_dirty = false; |
56 | 4.84k | vert_loaded_data_dirty = false; |
57 | 4.84k | record_loaded_data_dirty = false; |
58 | | |
59 | 4.84k | shape_index_start = 0; |
60 | 4.84k | shape_index_page_dirty = false; |
61 | | |
62 | 4.84k | shapeid_map_active = false; |
63 | 4.84k | shapeid_pages_certainly_mapped = -1; |
64 | | |
65 | 4.84k | vh.vs = this; |
66 | | |
67 | 4.84k | highest_shapeid_used = NullShapeId; |
68 | 4.84k | } Unexecuted instantiation: PCIDSK::CPCIDSKVectorSegment::CPCIDSKVectorSegment(PCIDSK::PCIDSKFile*, int, char const*) PCIDSK::CPCIDSKVectorSegment::CPCIDSKVectorSegment(PCIDSK::PCIDSKFile*, int, char const*) Line | Count | Source | 40 | 4.84k | : CPCIDSKSegment( fileIn, segmentIn, segment_pointer ) | 41 | | | 42 | 4.84k | { | 43 | 4.84k | base_initialized = false; | 44 | 4.84k | needs_swap = false; | 45 | | | 46 | 4.84k | total_shape_count = 0; | 47 | 4.84k | valid_shape_count = 0; | 48 | | | 49 | 4.84k | last_shapes_id = NullShapeId; | 50 | 4.84k | last_shapes_index = -1; | 51 | | | 52 | 4.84k | raw_loaded_data_offset = 0; | 53 | 4.84k | vert_loaded_data_offset = 0; | 54 | 4.84k | record_loaded_data_offset = 0; | 55 | 4.84k | raw_loaded_data_dirty = false; | 56 | 4.84k | vert_loaded_data_dirty = false; | 57 | 4.84k | record_loaded_data_dirty = false; | 58 | | | 59 | 4.84k | shape_index_start = 0; | 60 | 4.84k | shape_index_page_dirty = false; | 61 | | | 62 | 4.84k | shapeid_map_active = false; | 63 | 4.84k | shapeid_pages_certainly_mapped = -1; | 64 | | | 65 | 4.84k | vh.vs = this; | 66 | | | 67 | 4.84k | highest_shapeid_used = NullShapeId; | 68 | 4.84k | } |
|
69 | | |
70 | | /************************************************************************/ |
71 | | /* ~CPCIDSKVectorSegment() */ |
72 | | /************************************************************************/ |
73 | | |
74 | | CPCIDSKVectorSegment::~CPCIDSKVectorSegment() |
75 | | |
76 | 4.84k | { |
77 | 4.84k | try |
78 | 4.84k | { |
79 | 4.84k | Synchronize(); |
80 | 4.84k | } |
81 | 4.84k | catch( const PCIDSKException& e ) |
82 | 4.84k | { |
83 | 0 | fprintf(stderr, "Exception in ~CPCIDSKVectorSegment(): %s", e.what()); // ok |
84 | 0 | } |
85 | 4.84k | } |
86 | | |
87 | | /************************************************************************/ |
88 | | /* Synchronize() */ |
89 | | /************************************************************************/ |
90 | | |
91 | | void CPCIDSKVectorSegment::Synchronize() |
92 | 11.0k | { |
93 | 11.0k | if( base_initialized ) |
94 | 11.0k | { |
95 | 11.0k | FlushSegHeaderIfNeeded(); |
96 | | |
97 | 11.0k | FlushDataBuffer( sec_vert ); |
98 | 11.0k | FlushDataBuffer( sec_record ); |
99 | | |
100 | 11.0k | di[sec_vert].Flush(); |
101 | 11.0k | di[sec_record].Flush(); |
102 | | |
103 | 11.0k | FlushLoadedShapeIndex(); |
104 | | |
105 | 11.0k | if( GetHeader().GetInt( 192, 16 ) != total_shape_count |
106 | 1.50k | && file->GetUpdatable() ) |
107 | 1.50k | { |
108 | 1.50k | GetHeader().Put( total_shape_count, 192, 16 ); |
109 | 1.50k | FlushHeader(); |
110 | 1.50k | } |
111 | 11.0k | } |
112 | 11.0k | } |
113 | | |
114 | | /************************************************************************/ |
115 | | /* Initialize() */ |
116 | | /* */ |
117 | | /* Initialize the header of a new vector segment in a */ |
118 | | /* consistent state for an empty segment. */ |
119 | | /************************************************************************/ |
120 | | |
121 | | void CPCIDSKVectorSegment::Initialize() |
122 | | |
123 | 2.06k | { |
124 | 2.06k | needs_swap = !BigEndianSystem(); |
125 | | |
126 | | /* -------------------------------------------------------------------- */ |
127 | | /* Initialize the header that occurs within the regular segment */ |
128 | | /* data. */ |
129 | | /* -------------------------------------------------------------------- */ |
130 | 2.06k | vh.InitializeNew(); |
131 | | |
132 | | /* -------------------------------------------------------------------- */ |
133 | | /* Initialize the values in the generic segment header. */ |
134 | | /* -------------------------------------------------------------------- */ |
135 | 2.06k | PCIDSKBuffer &head = GetHeader(); |
136 | | |
137 | 2.06k | head.Put( "METRE", 160, 16 ); |
138 | 2.06k | head.Put( 1.0, 176, 16 ); |
139 | 2.06k | head.Put( 0, 192, 16 ); |
140 | 2.06k | head.Put( 0, 208, 16 ); |
141 | 2.06k | head.Put( 0, 224, 16 ); |
142 | 2.06k | head.Put( "", 240, 16 ); |
143 | 2.06k | head.Put( 0, 256, 16 ); |
144 | 2.06k | head.Put( 0, 272, 16 ); |
145 | | |
146 | | #ifdef PCIMAJORVERSION |
147 | | PCIDSK::ShapeField oFieldsDefault; |
148 | | oFieldsDefault.SetValue(std::vector<int32>{}); |
149 | | |
150 | | // Add the RingStart field, because it can't be added after |
151 | | // shapes have been added. This is a bug that should be properly fixed |
152 | | AddField(ATT_RINGSTART, |
153 | | PCIDSK::FieldTypeCountedInt, |
154 | | "", "", |
155 | | &oFieldsDefault); |
156 | | #endif |
157 | | |
158 | 2.06k | FlushHeader(); |
159 | 2.06k | } |
160 | | |
161 | | /************************************************************************/ |
162 | | /* LoadHeader() */ |
163 | | /* */ |
164 | | /* Initialize minimum information from the vector segment */ |
165 | | /* header. We defer this till an actual vector related action */ |
166 | | /* is taken. */ |
167 | | /************************************************************************/ |
168 | | |
169 | | void CPCIDSKVectorSegment::LoadHeader() |
170 | | |
171 | 19.9M | { |
172 | 19.9M | if( base_initialized ) |
173 | 19.9M | return; |
174 | | |
175 | 4.84k | base_initialized = true; |
176 | | |
177 | 4.84k | needs_swap = !BigEndianSystem(); |
178 | | |
179 | 4.84k | vh.InitializeExisting(); |
180 | | |
181 | | // When the IDB code deletes a shape, it simply writes a -1 |
182 | | // into the index. We need to know how many actual valid shapes |
183 | | // there are in the segment, so count them |
184 | 4.84k | valid_shape_count = 0; |
185 | 4.84k | ShapeId iShape = FindFirst(); |
186 | 965k | while (iShape != NullShapeId) |
187 | 960k | { |
188 | 960k | ++valid_shape_count; |
189 | 960k | iShape = FindNext(iShape); |
190 | 960k | } |
191 | 4.84k | } |
192 | | |
193 | | /************************************************************************/ |
194 | | /* ReadField() */ |
195 | | /* */ |
196 | | /* Read a value from the indicated offset in a section of the */ |
197 | | /* vector segment, and place the value into a ShapeField */ |
198 | | /* structure based on the passed in field type. */ |
199 | | /************************************************************************/ |
200 | | |
201 | | uint32 CPCIDSKVectorSegment::ReadField( uint32 offset, ShapeField& field, |
202 | | ShapeFieldType field_type, |
203 | | int section ) |
204 | | |
205 | 485k | { |
206 | 485k | switch( field_type ) |
207 | 485k | { |
208 | 98.9k | case FieldTypeInteger: |
209 | 98.9k | { |
210 | 98.9k | int32 value; |
211 | 98.9k | memcpy( &value, GetData( section, offset, nullptr, 4), 4 ); |
212 | 98.9k | if( needs_swap ) |
213 | 98.9k | SwapData( &value, 4, 1 ); |
214 | 98.9k | field.SetValue( value ); |
215 | 98.9k | return offset + 4; |
216 | 0 | } |
217 | | |
218 | 0 | case FieldTypeFloat: |
219 | 0 | { |
220 | 0 | float value; |
221 | 0 | memcpy( &value, GetData( section, offset, nullptr, 4), 4 ); |
222 | 0 | if( needs_swap ) |
223 | 0 | SwapData( &value, 4, 1 ); |
224 | 0 | field.SetValue( value ); |
225 | 0 | return offset + 4; |
226 | 0 | } |
227 | | |
228 | 62 | case FieldTypeDouble: |
229 | 62 | { |
230 | 62 | double value; |
231 | 62 | memcpy( &value, GetData( section, offset, nullptr, 8), 8 ); |
232 | 62 | if( needs_swap ) |
233 | 62 | SwapData( &value, 8, 1 ); |
234 | 62 | field.SetValue( value ); |
235 | 62 | return offset + 8; |
236 | 0 | } |
237 | | |
238 | 386k | case FieldTypeString: |
239 | 386k | { |
240 | 386k | int available; |
241 | 386k | char *srcdata = GetData( section, offset, &available, 1 ); |
242 | | |
243 | | // Simple case -- all initially available. |
244 | 386k | int string_len = 0; |
245 | | |
246 | 1.52M | while( srcdata[string_len] != '\0' && available - string_len > 0 ) |
247 | 1.13M | string_len++; |
248 | | |
249 | 386k | if( string_len < available && srcdata[string_len] == '\0' ) |
250 | 386k | { |
251 | 386k | std::string value( srcdata, string_len ); |
252 | 386k | field.SetValue( value ); |
253 | 386k | return offset + string_len + 1; |
254 | 386k | } |
255 | | |
256 | 82 | std::string value; |
257 | | |
258 | 2.16k | while( *srcdata != '\0' ) |
259 | 2.08k | { |
260 | 2.08k | value += *(srcdata++); |
261 | 2.08k | offset++; |
262 | 2.08k | available--; |
263 | 2.08k | if( available == 0 ) |
264 | 82 | srcdata = GetData( section, offset, &available, 1 ); |
265 | 2.08k | } |
266 | | |
267 | 82 | field.SetValue( value ); |
268 | 82 | return offset+1; |
269 | 386k | } |
270 | | |
271 | 0 | case FieldTypeCountedInt: |
272 | 0 | { |
273 | 0 | std::vector<int32> value; |
274 | 0 | int32 count; |
275 | 0 | char *srcdata = GetData( section, offset, nullptr, 4 ); |
276 | 0 | memcpy( &count, srcdata, 4 ); |
277 | 0 | if( needs_swap ) |
278 | 0 | SwapData( &count, 4, 1 ); |
279 | |
|
280 | 0 | value.resize( count ); |
281 | 0 | if( count > 0 ) |
282 | 0 | { |
283 | 0 | if( offset > std::numeric_limits<uint32>::max() - 8 ) |
284 | 0 | return ThrowPCIDSKException(0, "Invalid offset = %u", offset); |
285 | 0 | memcpy( &(value[0]), GetData(section,offset+4,nullptr,4*count), 4*count ); |
286 | 0 | if( needs_swap ) |
287 | 0 | SwapData( &(value[0]), 4, count ); |
288 | 0 | } |
289 | | |
290 | 0 | field.SetValue( value ); |
291 | 0 | return offset + 4 + 4*count; |
292 | 0 | } |
293 | | |
294 | 0 | default: |
295 | 0 | return ThrowPCIDSKException(0, "Unhandled field type %d", field_type); |
296 | 485k | } |
297 | 485k | } |
298 | | |
299 | | /************************************************************************/ |
300 | | /* WriteField() */ |
301 | | /* */ |
302 | | /* Write a field value into a buffer, growing the buffer if */ |
303 | | /* needed to hold the value. */ |
304 | | /************************************************************************/ |
305 | | |
306 | | uint32 CPCIDSKVectorSegment::WriteField( uint32 offset, |
307 | | const ShapeField& field, |
308 | | PCIDSKBuffer& buffer ) |
309 | | |
310 | 3.77M | { |
311 | | /* -------------------------------------------------------------------- */ |
312 | | /* How much space do we need for this value? */ |
313 | | /* -------------------------------------------------------------------- */ |
314 | 3.77M | uint32 item_size = 0; |
315 | | |
316 | 3.77M | switch( field.GetType() ) |
317 | 3.77M | { |
318 | 62.3k | case FieldTypeInteger: |
319 | 62.3k | item_size = 4; |
320 | 62.3k | break; |
321 | | |
322 | 0 | case FieldTypeFloat: |
323 | 0 | item_size = 4; |
324 | 0 | break; |
325 | | |
326 | 35.8k | case FieldTypeDouble: |
327 | 35.8k | item_size = 8; |
328 | 35.8k | break; |
329 | | |
330 | 3.68M | case FieldTypeString: |
331 | 3.68M | item_size = static_cast<uint32>(field.GetValueString().size()) + 1; |
332 | 3.68M | break; |
333 | | |
334 | 0 | case FieldTypeCountedInt: |
335 | 0 | item_size = static_cast<uint32>(field.GetValueCountedInt().size()) * 4 + 4; |
336 | 0 | break; |
337 | | |
338 | 0 | default: |
339 | 0 | assert( 0 ); |
340 | 0 | item_size = 0; |
341 | 0 | break; |
342 | 3.77M | } |
343 | | |
344 | | /* -------------------------------------------------------------------- */ |
345 | | /* Do we need to grow the buffer to hold this? Try to make it */ |
346 | | /* plenty larger. */ |
347 | | /* -------------------------------------------------------------------- */ |
348 | 3.77M | if( item_size + offset > (uint32) buffer.buffer_size ) |
349 | 815k | buffer.SetSize( buffer.buffer_size*2 + item_size ); |
350 | | |
351 | | /* -------------------------------------------------------------------- */ |
352 | | /* Write to the buffer, and byte swap if needed. */ |
353 | | /* -------------------------------------------------------------------- */ |
354 | 3.77M | switch( field.GetType() ) |
355 | 3.77M | { |
356 | 62.3k | case FieldTypeInteger: |
357 | 62.3k | { |
358 | 62.3k | int32 value = field.GetValueInteger(); |
359 | 62.3k | if( needs_swap ) |
360 | 62.3k | SwapData( &value, 4, 1 ); |
361 | 62.3k | memcpy( buffer.buffer+offset, &value, 4 ); |
362 | 62.3k | break; |
363 | 0 | } |
364 | | |
365 | 0 | case FieldTypeFloat: |
366 | 0 | { |
367 | 0 | float value = field.GetValueFloat(); |
368 | 0 | if( needs_swap ) |
369 | 0 | SwapData( &value, 4, 1 ); |
370 | 0 | memcpy( buffer.buffer+offset, &value, 4 ); |
371 | 0 | break; |
372 | 0 | } |
373 | | |
374 | 35.8k | case FieldTypeDouble: |
375 | 35.8k | { |
376 | 35.8k | double value = field.GetValueDouble(); |
377 | 35.8k | if( needs_swap ) |
378 | 35.8k | SwapData( &value, 8, 1 ); |
379 | 35.8k | memcpy( buffer.buffer+offset, &value, 8 ); |
380 | 35.8k | break; |
381 | 0 | } |
382 | | |
383 | 3.68M | case FieldTypeString: |
384 | 3.68M | { |
385 | 3.68M | std::string value = field.GetValueString(); |
386 | 3.68M | memcpy( buffer.buffer+offset, value.c_str(), item_size ); |
387 | 3.68M | break; |
388 | 0 | } |
389 | | |
390 | 0 | case FieldTypeCountedInt: |
391 | 0 | { |
392 | 0 | std::vector<int32> value = field.GetValueCountedInt(); |
393 | 0 | uint32 count = static_cast<uint32>(value.size()); |
394 | 0 | memcpy( buffer.buffer+offset, &count, 4 ); |
395 | 0 | if( count > 0 ) |
396 | 0 | { |
397 | 0 | memcpy( buffer.buffer+offset+4, &(value[0]), count * 4 ); |
398 | 0 | if( needs_swap ) |
399 | 0 | SwapData( buffer.buffer+offset, 4, count+1 ); |
400 | 0 | } |
401 | 0 | break; |
402 | 0 | } |
403 | | |
404 | 0 | default: |
405 | 0 | assert( 0 ); |
406 | 0 | break; |
407 | 3.77M | } |
408 | | |
409 | 3.77M | return offset + item_size; |
410 | 3.77M | } |
411 | | |
412 | | /************************************************************************/ |
413 | | /* GetData() */ |
414 | | /************************************************************************/ |
415 | | |
416 | | char *CPCIDSKVectorSegment::GetData( int section, uint32 offset, |
417 | | int *bytes_available, int min_bytes, |
418 | | bool update ) |
419 | | |
420 | 1.89M | { |
421 | 1.89M | if( min_bytes == 0 ) |
422 | 0 | min_bytes = 1; |
423 | | |
424 | | /* -------------------------------------------------------------------- */ |
425 | | /* Select the section to act on. */ |
426 | | /* -------------------------------------------------------------------- */ |
427 | 1.89M | PCIDSKBuffer *pbuf = nullptr; |
428 | 1.89M | uint32 *pbuf_offset = nullptr; |
429 | 1.89M | bool *pbuf_dirty = nullptr; |
430 | | |
431 | 1.89M | if( section == sec_raw ) |
432 | 523k | { |
433 | 523k | pbuf = &raw_loaded_data; |
434 | 523k | pbuf_offset = &raw_loaded_data_offset; |
435 | 523k | pbuf_dirty = &raw_loaded_data_dirty; |
436 | 523k | } |
437 | 1.36M | else if( section == sec_vert ) |
438 | 685k | { |
439 | 685k | pbuf = &vert_loaded_data; |
440 | 685k | pbuf_offset = &vert_loaded_data_offset; |
441 | 685k | pbuf_dirty = &vert_loaded_data_dirty; |
442 | 685k | } |
443 | 681k | else if( section == sec_record ) |
444 | 681k | { |
445 | 681k | pbuf = &record_loaded_data; |
446 | 681k | pbuf_offset = &record_loaded_data_offset; |
447 | 681k | pbuf_dirty = &record_loaded_data_dirty; |
448 | 681k | } |
449 | 0 | else |
450 | 0 | { |
451 | 0 | return (char*)ThrowPCIDSKExceptionPtr("Unexpected case"); |
452 | 0 | } |
453 | | |
454 | 1.89M | if( offset > std::numeric_limits<uint32>::max() - static_cast<uint32>(min_bytes) ) |
455 | 0 | return (char*)ThrowPCIDSKExceptionPtr("Invalid offset : %u", offset); |
456 | | |
457 | | /* -------------------------------------------------------------------- */ |
458 | | /* If the desired data is not within our loaded section, reload */ |
459 | | /* one or more blocks around the request. */ |
460 | | /* -------------------------------------------------------------------- */ |
461 | 1.89M | if( offset < *pbuf_offset |
462 | 1.89M | || offset+static_cast<uint32>(min_bytes) > *pbuf_offset + static_cast<uint32>(pbuf->buffer_size) ) |
463 | 10.4k | { |
464 | 10.4k | if( *pbuf_dirty ) |
465 | 2.47k | FlushDataBuffer( section ); |
466 | | |
467 | | // we want whole 8K blocks around the target region. |
468 | 10.4k | uint32 load_offset = offset - (offset % block_page_size); |
469 | 10.4k | int size = (offset + static_cast<uint32>(min_bytes) - load_offset + block_page_size - 1); |
470 | | |
471 | 10.4k | size -= (size % block_page_size); |
472 | | |
473 | | // If the request goes beyond the end of the file, and we are |
474 | | // in update mode, grow the segment by writing at the end of |
475 | | // the requested section. This will throw an exception if we |
476 | | // are unable to grow the file. |
477 | 10.4k | if( section != sec_raw |
478 | 5.41k | && load_offset + size > di[section].GetIndex()->size() * block_page_size |
479 | 5.41k | && update ) |
480 | 5.41k | { |
481 | 5.41k | PCIDSKBuffer zerobuf(block_page_size); |
482 | | |
483 | 5.41k | memset( zerobuf.buffer, 0, block_page_size ); |
484 | 5.41k | WriteSecToFile( section, zerobuf.buffer, |
485 | 5.41k | (load_offset + size) / block_page_size - 1, 1 ); |
486 | 5.41k | } |
487 | | |
488 | 10.4k | *pbuf_offset = load_offset; |
489 | 10.4k | pbuf->SetSize( size ); |
490 | | |
491 | 10.4k | ReadSecFromFile( section, pbuf->buffer, |
492 | 10.4k | load_offset / block_page_size, size / block_page_size ); |
493 | 10.4k | } |
494 | | |
495 | | /* -------------------------------------------------------------------- */ |
496 | | /* If an update request goes beyond the end of the last data */ |
497 | | /* byte in a data section, then update the bytes used. Now */ |
498 | | /* read into our buffer. */ |
499 | | /* -------------------------------------------------------------------- */ |
500 | 1.89M | if( section != sec_raw |
501 | 1.36M | && offset + min_bytes > di[section].GetSectionEnd() ) |
502 | 1.36M | di[section].SetSectionEnd( offset + min_bytes ); |
503 | | |
504 | | /* -------------------------------------------------------------------- */ |
505 | | /* Return desired info. */ |
506 | | /* -------------------------------------------------------------------- */ |
507 | 1.89M | if( bytes_available != nullptr ) |
508 | 386k | *bytes_available = *pbuf_offset + pbuf->buffer_size - offset; |
509 | | |
510 | 1.89M | if( update ) |
511 | 1.36M | *pbuf_dirty = true; |
512 | | |
513 | 1.89M | return pbuf->buffer + offset - *pbuf_offset; |
514 | 1.89M | } |
515 | | |
516 | | /************************************************************************/ |
517 | | /* ReadSecFromFile() */ |
518 | | /* */ |
519 | | /* Read one or more blocks from the desired "section" of the */ |
520 | | /* segment data, going through the block pointer map for */ |
521 | | /* vect/record sections. */ |
522 | | /************************************************************************/ |
523 | | |
524 | | void CPCIDSKVectorSegment::ReadSecFromFile( int section, char *buffer, |
525 | | int block_offset, |
526 | | int block_count ) |
527 | | |
528 | 10.4k | { |
529 | | /* -------------------------------------------------------------------- */ |
530 | | /* Raw is a simple case, directly gulp. */ |
531 | | /* -------------------------------------------------------------------- */ |
532 | 10.4k | if( section == sec_raw ) |
533 | 5.04k | { |
534 | 5.04k | ReadFromFile( buffer, static_cast<uint64>(block_offset)*static_cast<uint32>(block_page_size), |
535 | 5.04k | block_count*block_page_size ); |
536 | 5.04k | return; |
537 | 5.04k | } |
538 | | |
539 | | /* -------------------------------------------------------------------- */ |
540 | | /* Process one 8K block at a time in case they are discontiguous */ |
541 | | /* which they often are. */ |
542 | | /* -------------------------------------------------------------------- */ |
543 | 5.41k | int i; |
544 | 5.41k | const std::vector<uint32> *block_map = di[section].GetIndex(); |
545 | | |
546 | 5.41k | if( block_count + block_offset > (int) block_map->size() ) |
547 | 0 | { |
548 | 0 | return ThrowPCIDSKException("Assertion failed: block_count(=%d) + block_offset(=%d) <= block_map->size()(=%d)", |
549 | 0 | block_count, block_offset, (int) block_map->size() ); |
550 | 0 | } |
551 | | |
552 | 12.8k | for( i = 0; i < block_count; i++ ) |
553 | 7.44k | { |
554 | 7.44k | ReadFromFile( buffer + i * block_page_size, |
555 | 7.44k | block_page_size * static_cast<uint64>((*block_map)[block_offset+i]), |
556 | 7.44k | block_page_size ); |
557 | 7.44k | } |
558 | 5.41k | } |
559 | | |
560 | | /************************************************************************/ |
561 | | /* FlushDataBuffer() */ |
562 | | /* */ |
563 | | /* Flush the indicated data buffer to disk if it is marked */ |
564 | | /* dirty. */ |
565 | | /************************************************************************/ |
566 | | |
567 | | void CPCIDSKVectorSegment::FlushDataBuffer( int section ) |
568 | | |
569 | 24.5k | { |
570 | | /* -------------------------------------------------------------------- */ |
571 | | /* Select the section to act on. */ |
572 | | /* -------------------------------------------------------------------- */ |
573 | 24.5k | PCIDSKBuffer *pbuf = nullptr; |
574 | 24.5k | uint32 *pbuf_offset = nullptr; |
575 | 24.5k | bool *pbuf_dirty = nullptr; |
576 | | |
577 | 24.5k | if( section == sec_raw ) |
578 | 0 | { |
579 | 0 | pbuf = &raw_loaded_data; |
580 | 0 | pbuf_offset = &raw_loaded_data_offset; |
581 | 0 | pbuf_dirty = &raw_loaded_data_dirty; |
582 | 0 | } |
583 | 24.5k | else if( section == sec_vert ) |
584 | 11.5k | { |
585 | 11.5k | pbuf = &vert_loaded_data; |
586 | 11.5k | pbuf_offset = &vert_loaded_data_offset; |
587 | 11.5k | pbuf_dirty = &vert_loaded_data_dirty; |
588 | 11.5k | } |
589 | 13.0k | else if( section == sec_record ) |
590 | 13.0k | { |
591 | 13.0k | pbuf = &record_loaded_data; |
592 | 13.0k | pbuf_offset = &record_loaded_data_offset; |
593 | 13.0k | pbuf_dirty = &record_loaded_data_dirty; |
594 | 13.0k | } |
595 | 0 | else |
596 | 0 | { |
597 | 0 | return ThrowPCIDSKException("Unexpected case"); |
598 | 0 | } |
599 | | |
600 | 24.5k | if( ! *pbuf_dirty || pbuf->buffer_size == 0 ) |
601 | 19.1k | return; |
602 | | |
603 | | /* -------------------------------------------------------------------- */ |
604 | | /* We need to write something. */ |
605 | | /* -------------------------------------------------------------------- */ |
606 | 24.5k | assert( (pbuf->buffer_size % block_page_size) == 0 ); |
607 | 5.41k | assert( (*pbuf_offset % block_page_size) == 0 ); |
608 | | |
609 | 5.41k | WriteSecToFile( section, pbuf->buffer, |
610 | 5.41k | *pbuf_offset / block_page_size, |
611 | 5.41k | pbuf->buffer_size / block_page_size ); |
612 | | |
613 | 5.41k | *pbuf_dirty = false; |
614 | 5.41k | } |
615 | | |
616 | | /************************************************************************/ |
617 | | /* WriteSecToFile() */ |
618 | | /* */ |
619 | | /* Read one or more blocks from the desired "section" of the */ |
620 | | /* segment data, going through the block pointer map for */ |
621 | | /* vect/record sections. */ |
622 | | /************************************************************************/ |
623 | | |
624 | | void CPCIDSKVectorSegment::WriteSecToFile( int section, char *buffer, |
625 | | int block_offset, |
626 | | int block_count ) |
627 | | |
628 | 10.8k | { |
629 | | /* -------------------------------------------------------------------- */ |
630 | | /* Raw is a simple case, directly gulp. */ |
631 | | /* -------------------------------------------------------------------- */ |
632 | 10.8k | if( section == sec_raw ) |
633 | 0 | { |
634 | 0 | WriteToFile( buffer, block_offset*block_page_size, |
635 | 0 | block_count*block_page_size ); |
636 | 0 | return; |
637 | 0 | } |
638 | | |
639 | | /* -------------------------------------------------------------------- */ |
640 | | /* Do we need to grow this data section to be able to do the */ |
641 | | /* write? */ |
642 | | /* -------------------------------------------------------------------- */ |
643 | 10.8k | const std::vector<uint32> *block_map = di[section].GetIndex(); |
644 | | |
645 | 10.8k | if( block_count + block_offset > (int) block_map->size() ) |
646 | 5.41k | { |
647 | 5.41k | vh.GrowBlockIndex( section, |
648 | 5.41k | block_count + block_offset - static_cast<int>(block_map->size()) ); |
649 | 5.41k | } |
650 | | |
651 | | /* -------------------------------------------------------------------- */ |
652 | | /* Process one 8K block at a time in case they are discontiguous */ |
653 | | /* which they often are. */ |
654 | | /* -------------------------------------------------------------------- */ |
655 | 10.8k | int i; |
656 | 23.6k | for( i = 0; i < block_count; i++ ) |
657 | 12.8k | { |
658 | 12.8k | WriteToFile( buffer + i * block_page_size, |
659 | 12.8k | block_page_size * (*block_map)[block_offset+i], |
660 | 12.8k | block_page_size ); |
661 | 12.8k | } |
662 | 10.8k | } |
663 | | |
664 | | /************************************************************************/ |
665 | | /* GetProjection() */ |
666 | | /************************************************************************/ |
667 | | |
668 | | std::vector<double> CPCIDSKVectorSegment::GetProjection( std::string &geosys ) |
669 | | |
670 | 4.77k | { |
671 | 4.77k | LoadHeader(); |
672 | | |
673 | | /* -------------------------------------------------------------------- */ |
674 | | /* Fetch the projparms string from the proj section of the */ |
675 | | /* vector segment header. */ |
676 | | /* -------------------------------------------------------------------- */ |
677 | 4.77k | ShapeField projparms; |
678 | | |
679 | 4.77k | ReadField( vh.section_offsets[hsec_proj]+32, projparms, |
680 | 4.77k | FieldTypeString, sec_raw ); |
681 | | |
682 | | /* -------------------------------------------------------------------- */ |
683 | | /* Read the geosys (units) string from SDH5.VEC1 in the segment */ |
684 | | /* header. */ |
685 | | /* -------------------------------------------------------------------- */ |
686 | 4.77k | GetHeader().Get( 160, 16, geosys, 0 ); // do not unpad! |
687 | | |
688 | 4.77k | return ProjParamsFromText( geosys, projparms.GetValueString() ); |
689 | 4.77k | } |
690 | | |
691 | | /************************************************************************/ |
692 | | /* SetProjection() */ |
693 | | /************************************************************************/ |
694 | | |
695 | | void CPCIDSKVectorSegment::SetProjection( const std::string& geosys, |
696 | | const std::vector<double>& params ) |
697 | | |
698 | 298 | { |
699 | 298 | LoadHeader(); |
700 | | |
701 | | /* -------------------------------------------------------------------- */ |
702 | | /* Apply parameters in the vector segment "proj" header section. */ |
703 | | /* -------------------------------------------------------------------- */ |
704 | 298 | PCIDSKBuffer proj(32); |
705 | 298 | uint32 proj_size; |
706 | 298 | ShapeField value; |
707 | | |
708 | 298 | value.SetValue( ProjParamsToText( params ) ); |
709 | | |
710 | 298 | ReadFromFile( proj.buffer, vh.section_offsets[hsec_proj], 32 ); |
711 | 298 | proj_size = WriteField( 32, value, proj ); |
712 | | |
713 | 298 | vh.GrowSection( hsec_proj, proj_size ); |
714 | 298 | WriteToFile( proj.buffer, vh.section_offsets[hsec_proj], proj_size ); |
715 | | |
716 | | /* -------------------------------------------------------------------- */ |
717 | | /* Write the geosys string to the generic segment header. */ |
718 | | /* -------------------------------------------------------------------- */ |
719 | 298 | GetHeader().Put( geosys.c_str(), 160, 16 ); |
720 | 298 | FlushHeader(); |
721 | 298 | } |
722 | | |
723 | | /************************************************************************/ |
724 | | /* IndexFromShapeId() */ |
725 | | /* */ |
726 | | /* Translate a shapeid into a shape index. Several mechanisms */ |
727 | | /* are used to accelerate this when possible. */ |
728 | | /************************************************************************/ |
729 | | |
730 | | int CPCIDSKVectorSegment::IndexFromShapeId( ShapeId id ) |
731 | | |
732 | 2.32M | { |
733 | 2.32M | if( id == NullShapeId ) |
734 | 0 | return -1; |
735 | | |
736 | 2.32M | LoadHeader(); |
737 | | |
738 | | /* -------------------------------------------------------------------- */ |
739 | | /* Does this match our last lookup? */ |
740 | | /* -------------------------------------------------------------------- */ |
741 | 2.32M | if( id == last_shapes_id ) |
742 | 1.56M | return last_shapes_index; |
743 | | |
744 | | /* -------------------------------------------------------------------- */ |
745 | | /* Is this the next shapeid in sequence, and is it in our */ |
746 | | /* loaded index cache? */ |
747 | | /* -------------------------------------------------------------------- */ |
748 | 758k | if( id == last_shapes_id + 1 |
749 | 613k | && last_shapes_index + 1 >= shape_index_start |
750 | 613k | && last_shapes_index + 1 < shape_index_start + (int) shape_index_ids.size() ) |
751 | 613k | { |
752 | 613k | last_shapes_index++; |
753 | 613k | last_shapes_id++; |
754 | 613k | return last_shapes_index; |
755 | 613k | } |
756 | | |
757 | | /* -------------------------------------------------------------------- */ |
758 | | /* Activate the shapeid map, if it is not already active. */ |
759 | | /* -------------------------------------------------------------------- */ |
760 | 145k | if( !shapeid_map_active ) |
761 | 147 | { |
762 | 147 | PopulateShapeIdMap(); |
763 | 147 | } |
764 | | |
765 | | /* -------------------------------------------------------------------- */ |
766 | | /* Is this already in our shapeid map? */ |
767 | | /* -------------------------------------------------------------------- */ |
768 | 145k | if( shapeid_map.count( id ) == 1 ) |
769 | 145k | return shapeid_map[id]; |
770 | | |
771 | 0 | return -1; |
772 | 145k | } |
773 | | |
774 | | /************************************************************************/ |
775 | | /* LoadShapeIdPage() */ |
776 | | /************************************************************************/ |
777 | | |
778 | | void CPCIDSKVectorSegment::LoadShapeIdPage( int page ) |
779 | | |
780 | 3.18k | { |
781 | | /* -------------------------------------------------------------------- */ |
782 | | /* Load a chunk of shape index information into a */ |
783 | | /* PCIDSKBuffer. */ |
784 | | /* -------------------------------------------------------------------- */ |
785 | 3.18k | uint32 shape_index_byte_offset = |
786 | 3.18k | vh.section_offsets[hsec_shape] |
787 | 3.18k | + di[sec_record].offset_on_disk_within_section |
788 | 3.18k | + di[sec_record].size_on_disk + 4; |
789 | | |
790 | 3.18k | int entries_to_load = shapeid_page_size; |
791 | | |
792 | 3.18k | shape_index_start = page * shapeid_page_size; |
793 | 3.18k | if( shape_index_start + entries_to_load > total_shape_count ) |
794 | 2.48k | entries_to_load = total_shape_count - shape_index_start; |
795 | | |
796 | 3.18k | PCIDSKBuffer wrk_index; |
797 | 3.18k | if( entries_to_load < 0 || entries_to_load > std::numeric_limits<int>::max() / 12 ) |
798 | 0 | return ThrowPCIDSKException("Invalid entries_to_load = %d", entries_to_load); |
799 | 3.18k | wrk_index.SetSize( entries_to_load * 12 ); |
800 | | |
801 | 3.18k | ReadFromFile( wrk_index.buffer, |
802 | 3.18k | shape_index_byte_offset + static_cast<uint64>(shape_index_start)*12, |
803 | 3.18k | wrk_index.buffer_size ); |
804 | | |
805 | | /* -------------------------------------------------------------------- */ |
806 | | /* Parse into the vectors for easier use. */ |
807 | | /* -------------------------------------------------------------------- */ |
808 | 3.18k | int i; |
809 | | |
810 | 3.18k | shape_index_ids.resize( entries_to_load ); |
811 | 3.18k | shape_index_vertex_off.resize( entries_to_load ); |
812 | 3.18k | shape_index_record_off.resize( entries_to_load ); |
813 | | |
814 | 963k | for( i = 0; i < entries_to_load; i++ ) |
815 | 960k | { |
816 | 960k | memcpy( &(shape_index_ids[i]), wrk_index.buffer + i*12, 4 ); |
817 | 960k | memcpy( &(shape_index_vertex_off[i]), wrk_index.buffer + i*12+4, 4 ); |
818 | 960k | memcpy( &(shape_index_record_off[i]), wrk_index.buffer + i*12+8, 4 ); |
819 | 960k | } |
820 | | |
821 | 3.18k | if( needs_swap && entries_to_load > 0 ) |
822 | 2.71k | { |
823 | 2.71k | SwapData( &(shape_index_ids[0]), 4, entries_to_load ); |
824 | 2.71k | SwapData( &(shape_index_vertex_off[0]), 4, entries_to_load ); |
825 | 2.71k | SwapData( &(shape_index_record_off[0]), 4, entries_to_load ); |
826 | 2.71k | } |
827 | | |
828 | 3.18k | PushLoadedIndexIntoMap(); |
829 | 3.18k | } |
830 | | |
831 | | /************************************************************************/ |
832 | | /* AccessShapeByIndex() */ |
833 | | /* */ |
834 | | /* This method is responsible for loading the set of */ |
835 | | /* information for shape "shape_index" into the shape_index data */ |
836 | | /* structures if it is not already there. */ |
837 | | /************************************************************************/ |
838 | | |
839 | | void CPCIDSKVectorSegment::AccessShapeByIndex( int shape_index ) |
840 | | |
841 | 3.01M | { |
842 | 3.01M | LoadHeader(); |
843 | | |
844 | | /* -------------------------------------------------------------------- */ |
845 | | /* Is the requested index already loaded? */ |
846 | | /* -------------------------------------------------------------------- */ |
847 | 3.01M | if( shape_index >= shape_index_start |
848 | 3.01M | && shape_index < shape_index_start + (int) shape_index_ids.size() ) |
849 | 2.32M | return; |
850 | | |
851 | | // this is for requesting the next shapeindex after shapecount on |
852 | | // a partial page. |
853 | 688k | if( shape_index == total_shape_count |
854 | 685k | && (int) shape_index_ids.size() < shapeid_page_size |
855 | 685k | && total_shape_count == (int) shape_index_ids.size() + shape_index_start ) |
856 | 685k | return; |
857 | | |
858 | | /* -------------------------------------------------------------------- */ |
859 | | /* If the currently loaded shapeindex is dirty, we should write */ |
860 | | /* it now. */ |
861 | | /* -------------------------------------------------------------------- */ |
862 | 3.18k | FlushLoadedShapeIndex(); |
863 | | |
864 | | /* -------------------------------------------------------------------- */ |
865 | | /* Load the page of shapeid information for this shape index. */ |
866 | | /* -------------------------------------------------------------------- */ |
867 | 3.18k | LoadShapeIdPage( shape_index / shapeid_page_size ); |
868 | 3.18k | } |
869 | | |
870 | | /************************************************************************/ |
871 | | /* PushLoadedIndexIntoMap() */ |
872 | | /************************************************************************/ |
873 | | |
874 | | void CPCIDSKVectorSegment::PushLoadedIndexIntoMap() |
875 | | |
876 | 3.33k | { |
877 | | /* -------------------------------------------------------------------- */ |
878 | | /* If the shapeid map is active, apply the current pages */ |
879 | | /* shapeids if it does not already appear to have been */ |
880 | | /* applied. */ |
881 | | /* -------------------------------------------------------------------- */ |
882 | 3.33k | int loaded_page = shape_index_start / shapeid_page_size; |
883 | | |
884 | 3.33k | if( shapeid_map_active && !shape_index_ids.empty() ) |
885 | 147 | { |
886 | 147 | unsigned int i; |
887 | | |
888 | 294 | for( i = 0; i < shape_index_ids.size(); i++ ) |
889 | 147 | { |
890 | 147 | if( shape_index_ids[i] != NullShapeId ) |
891 | 147 | shapeid_map[shape_index_ids[i]] = i+shape_index_start; |
892 | 147 | } |
893 | | |
894 | 147 | if( loaded_page == shapeid_pages_certainly_mapped+1 ) |
895 | 147 | shapeid_pages_certainly_mapped++; |
896 | 147 | } |
897 | 3.33k | } |
898 | | |
899 | | /************************************************************************/ |
900 | | /* PopulateShapeIdMap() */ |
901 | | /* */ |
902 | | /* Completely populate the shapeid->index map. */ |
903 | | /************************************************************************/ |
904 | | |
905 | | void CPCIDSKVectorSegment::PopulateShapeIdMap() |
906 | | |
907 | 147 | { |
908 | | /* -------------------------------------------------------------------- */ |
909 | | /* Enable shapeid_map mode, and load the current page. */ |
910 | | /* -------------------------------------------------------------------- */ |
911 | 147 | if( !shapeid_map_active ) |
912 | 147 | { |
913 | 147 | shapeid_map_active = true; |
914 | 147 | PushLoadedIndexIntoMap(); |
915 | 147 | } |
916 | | |
917 | | /* -------------------------------------------------------------------- */ |
918 | | /* Load all outstanding pages. */ |
919 | | /* -------------------------------------------------------------------- */ |
920 | 147 | int shapeid_pages = DIV_ROUND_UP(total_shape_count, shapeid_page_size); |
921 | | |
922 | 147 | while( shapeid_pages_certainly_mapped+1 < shapeid_pages ) |
923 | 0 | { |
924 | 0 | LoadShapeIdPage( shapeid_pages_certainly_mapped+1 ); |
925 | 0 | } |
926 | 147 | } |
927 | | |
928 | | /************************************************************************/ |
929 | | /* FindNextValidByIndex() */ |
930 | | /************************************************************************/ |
931 | | /** |
932 | | * Find the next shape and the given shape index in the segment |
933 | | * (including deleted shapes), if the shape at nIndex is NullShapeId then |
934 | | * return the nexrt valid shape ID |
935 | | * |
936 | | * @param nIndex the index into |
937 | | */ |
938 | | ShapeId CPCIDSKVectorSegment::FindNextValidByIndex(int nIndex) |
939 | 965k | { |
940 | 965k | LoadHeader(); |
941 | | |
942 | 965k | if (total_shape_count == 0 || nIndex >= total_shape_count) |
943 | 4.84k | return NullShapeId; |
944 | | |
945 | | |
946 | 960k | for (int nShapeIndex = nIndex; nShapeIndex < total_shape_count; ++nShapeIndex) |
947 | 960k | { |
948 | | // set up shape_index_ids array |
949 | 960k | AccessShapeByIndex(nShapeIndex); |
950 | | |
951 | 960k | int32 nNextShapeId = shape_index_ids[nShapeIndex - shape_index_start]; |
952 | 960k | if (nNextShapeId != NullShapeId) |
953 | 960k | { |
954 | 960k | last_shapes_id = nNextShapeId; |
955 | 960k | last_shapes_index = nShapeIndex; |
956 | 960k | return last_shapes_id; |
957 | 960k | } |
958 | 960k | } |
959 | | |
960 | 0 | return NullShapeId; |
961 | 960k | } |
962 | | |
963 | | /************************************************************************/ |
964 | | /* FindFirst() */ |
965 | | /************************************************************************/ |
966 | | |
967 | | ShapeId CPCIDSKVectorSegment::FindFirst() |
968 | 4.84k | { |
969 | 4.84k | return FindNextValidByIndex(0); |
970 | 4.84k | } |
971 | | |
972 | | /************************************************************************/ |
973 | | /* FindNext() */ |
974 | | /************************************************************************/ |
975 | | |
976 | | ShapeId CPCIDSKVectorSegment::FindNext( ShapeId previous_id ) |
977 | 960k | { |
978 | 960k | if( previous_id == NullShapeId ) |
979 | 0 | return FindFirst(); |
980 | | |
981 | 960k | int previous_index = IndexFromShapeId( previous_id ); |
982 | | |
983 | 960k | return FindNextValidByIndex(previous_index+1); |
984 | 960k | } |
985 | | |
986 | | /************************************************************************/ |
987 | | /* GetShapeCount() */ |
988 | | /************************************************************************/ |
989 | | |
990 | | int CPCIDSKVectorSegment::GetShapeCount() |
991 | | |
992 | 0 | { |
993 | 0 | LoadHeader(); |
994 | |
|
995 | 0 | return valid_shape_count; |
996 | 0 | } |
997 | | |
998 | | /************************************************************************/ |
999 | | /* GetVertices() */ |
1000 | | /************************************************************************/ |
1001 | | |
1002 | | void CPCIDSKVectorSegment::GetVertices( ShapeId shape_id, |
1003 | | std::vector<ShapeVertex> &vertices ) |
1004 | | |
1005 | 0 | { |
1006 | 0 | int shape_index = IndexFromShapeId( shape_id ); |
1007 | |
|
1008 | 0 | if( shape_index == -1 ) |
1009 | 0 | return ThrowPCIDSKException( "Attempt to call GetVertices() on non-existing shape id '%d'.", |
1010 | 0 | (int) shape_id ); |
1011 | | |
1012 | 0 | AccessShapeByIndex( shape_index ); |
1013 | |
|
1014 | 0 | uint32 vert_off = shape_index_vertex_off[shape_index - shape_index_start]; |
1015 | 0 | uint32 vertex_count; |
1016 | |
|
1017 | 0 | if( vert_off == 0xffffffff ) |
1018 | 0 | { |
1019 | 0 | vertices.resize(0); |
1020 | 0 | return; |
1021 | 0 | } |
1022 | | |
1023 | 0 | if( vert_off > std::numeric_limits<uint32>::max() - 4 ) |
1024 | 0 | return ThrowPCIDSKException( "Invalid vert_off = %u", vert_off); |
1025 | 0 | memcpy( &vertex_count, GetData( sec_vert, vert_off+4, nullptr, 4 ), 4 ); |
1026 | 0 | if( needs_swap ) |
1027 | 0 | SwapData( &vertex_count, 4, 1 ); |
1028 | |
|
1029 | 0 | try |
1030 | 0 | { |
1031 | 0 | vertices.resize( vertex_count ); |
1032 | 0 | } |
1033 | 0 | catch( const std::exception& ex ) |
1034 | 0 | { |
1035 | 0 | return ThrowPCIDSKException("Out of memory allocating vertices(%u): %s", |
1036 | 0 | vertex_count, ex.what()); |
1037 | 0 | } |
1038 | | |
1039 | | // We ought to change this to process the available data and |
1040 | | // then request more. |
1041 | 0 | if( vertex_count > 0 ) |
1042 | 0 | { |
1043 | 0 | if( vert_off > std::numeric_limits<uint32>::max() - 8 ) |
1044 | 0 | return ThrowPCIDSKException( "Invalid vert_off = %u", vert_off); |
1045 | 0 | memcpy( &(vertices[0]), |
1046 | 0 | GetData( sec_vert, vert_off+8, nullptr, vertex_count*24), |
1047 | 0 | vertex_count * 24 ); |
1048 | 0 | if( needs_swap ) |
1049 | 0 | SwapData( &(vertices[0]), 8, vertex_count*3 ); |
1050 | 0 | } |
1051 | 0 | } |
1052 | | |
1053 | | /************************************************************************/ |
1054 | | /* GetFieldCount() */ |
1055 | | /************************************************************************/ |
1056 | | |
1057 | | int CPCIDSKVectorSegment::GetFieldCount() |
1058 | | |
1059 | 5.67M | { |
1060 | 5.67M | LoadHeader(); |
1061 | | |
1062 | 5.67M | return static_cast<int>(vh.field_names.size()); |
1063 | 5.67M | } |
1064 | | |
1065 | | /************************************************************************/ |
1066 | | /* GetFieldName() */ |
1067 | | /************************************************************************/ |
1068 | | |
1069 | | std::string CPCIDSKVectorSegment::GetFieldName( int field_index ) |
1070 | | |
1071 | 3.61M | { |
1072 | 3.61M | LoadHeader(); |
1073 | | |
1074 | 3.61M | return vh.field_names[field_index]; |
1075 | 3.61M | } |
1076 | | |
1077 | | /************************************************************************/ |
1078 | | /* GetFieldDescription() */ |
1079 | | /************************************************************************/ |
1080 | | |
1081 | | std::string CPCIDSKVectorSegment::GetFieldDescription( int field_index ) |
1082 | | |
1083 | 0 | { |
1084 | 0 | LoadHeader(); |
1085 | |
|
1086 | 0 | return vh.field_descriptions[field_index]; |
1087 | 0 | } |
1088 | | |
1089 | | /************************************************************************/ |
1090 | | /* GetFieldType() */ |
1091 | | /************************************************************************/ |
1092 | | |
1093 | | ShapeFieldType CPCIDSKVectorSegment::GetFieldType( int field_index ) |
1094 | | |
1095 | 3.61M | { |
1096 | 3.61M | LoadHeader(); |
1097 | | |
1098 | 3.61M | return vh.field_types[field_index]; |
1099 | 3.61M | } |
1100 | | |
1101 | | /************************************************************************/ |
1102 | | /* GetFieldFormat() */ |
1103 | | /************************************************************************/ |
1104 | | |
1105 | | std::string CPCIDSKVectorSegment::GetFieldFormat( int field_index ) |
1106 | | |
1107 | 0 | { |
1108 | 0 | LoadHeader(); |
1109 | |
|
1110 | 0 | return vh.field_formats[field_index]; |
1111 | 0 | } |
1112 | | |
1113 | | /************************************************************************/ |
1114 | | /* GetFieldDefault() */ |
1115 | | /************************************************************************/ |
1116 | | |
1117 | | ShapeField CPCIDSKVectorSegment::GetFieldDefault( int field_index ) |
1118 | | |
1119 | 0 | { |
1120 | 0 | LoadHeader(); |
1121 | |
|
1122 | 0 | return vh.field_defaults[field_index]; |
1123 | 0 | } |
1124 | | |
1125 | | /************************************************************************/ |
1126 | | /* GetFields() */ |
1127 | | /************************************************************************/ |
1128 | | |
1129 | | void CPCIDSKVectorSegment::GetFields( ShapeId id, |
1130 | | std::vector<ShapeField>& list ) |
1131 | | |
1132 | 0 | { |
1133 | 0 | unsigned int i; |
1134 | 0 | int shape_index = IndexFromShapeId( id ); |
1135 | |
|
1136 | 0 | if( shape_index == -1 ) |
1137 | 0 | return ThrowPCIDSKException( "Attempt to call GetFields() on non-existing shape id '%d'.", |
1138 | 0 | (int) id ); |
1139 | | |
1140 | 0 | AccessShapeByIndex( shape_index ); |
1141 | |
|
1142 | 0 | uint32 offset = shape_index_record_off[shape_index - shape_index_start]; |
1143 | |
|
1144 | 0 | list.resize(vh.field_names.size()); |
1145 | |
|
1146 | 0 | if( offset == 0xffffffff ) |
1147 | 0 | { |
1148 | 0 | for( i = 0; i < vh.field_names.size(); i++ ) |
1149 | 0 | list[i] = vh.field_defaults[i]; |
1150 | 0 | } |
1151 | 0 | else |
1152 | 0 | { |
1153 | 0 | offset += 4; // skip size |
1154 | |
|
1155 | 0 | for( i = 0; i < vh.field_names.size(); i++ ) |
1156 | 0 | offset = ReadField( offset, list[i], vh.field_types[i], sec_record ); |
1157 | 0 | } |
1158 | 0 | } |
1159 | | |
1160 | | /************************************************************************/ |
1161 | | /* AddField() */ |
1162 | | /************************************************************************/ |
1163 | | |
1164 | | void CPCIDSKVectorSegment::AddField( const std::string& name, ShapeFieldType type, |
1165 | | const std::string& description, |
1166 | | const std::string& format, |
1167 | | ShapeField *default_value ) |
1168 | | |
1169 | 52.1k | { |
1170 | 52.1k | ShapeField fallback_default; |
1171 | | |
1172 | 52.1k | LoadHeader(); |
1173 | | |
1174 | | /* -------------------------------------------------------------------- */ |
1175 | | /* If we have existing features, we should go through adding */ |
1176 | | /* this new field. */ |
1177 | | /* -------------------------------------------------------------------- */ |
1178 | 52.1k | if( total_shape_count > 0 ) |
1179 | 64 | { |
1180 | 64 | return ThrowPCIDSKException( "Support for adding fields in populated layers " |
1181 | 64 | "has not yet been implemented." ); |
1182 | 64 | } |
1183 | | |
1184 | | /* -------------------------------------------------------------------- */ |
1185 | | /* If no default is provided, use the obvious value. */ |
1186 | | /* -------------------------------------------------------------------- */ |
1187 | 52.0k | if( default_value == nullptr ) |
1188 | 52.0k | { |
1189 | 52.0k | switch( type ) |
1190 | 52.0k | { |
1191 | 0 | case FieldTypeFloat: |
1192 | 0 | fallback_default.SetValue( (float) 0.0 ); |
1193 | 0 | break; |
1194 | 63 | case FieldTypeDouble: |
1195 | 63 | fallback_default.SetValue( (double) 0.0 ); |
1196 | 63 | break; |
1197 | 42 | case FieldTypeInteger: |
1198 | 42 | fallback_default.SetValue( (int32) 0 ); |
1199 | 42 | break; |
1200 | 0 | case FieldTypeCountedInt: |
1201 | 0 | { |
1202 | 0 | std::vector<int32> empty_list; |
1203 | 0 | fallback_default.SetValue( empty_list ); |
1204 | 0 | break; |
1205 | 0 | } |
1206 | 51.9k | case FieldTypeString: |
1207 | 51.9k | fallback_default.SetValue( "" ); |
1208 | 51.9k | break; |
1209 | | |
1210 | 0 | case FieldTypeNone: |
1211 | 0 | break; |
1212 | 52.0k | } |
1213 | | |
1214 | 52.0k | default_value = &fallback_default; |
1215 | 52.0k | } |
1216 | | |
1217 | | /* -------------------------------------------------------------------- */ |
1218 | | /* Make sure the default field is of the correct type. */ |
1219 | | /* -------------------------------------------------------------------- */ |
1220 | 52.0k | if( default_value->GetType() != type ) |
1221 | 0 | { |
1222 | 0 | return ThrowPCIDSKException( "Attempt to add field with a default value of " |
1223 | 0 | "a different type than the field." ); |
1224 | 0 | } |
1225 | | |
1226 | 52.0k | if( type == FieldTypeNone ) |
1227 | 0 | { |
1228 | 0 | return ThrowPCIDSKException( "Creating fields of type None not supported." ); |
1229 | 0 | } |
1230 | | |
1231 | | /* -------------------------------------------------------------------- */ |
1232 | | /* Add the field to the definition list. */ |
1233 | | /* -------------------------------------------------------------------- */ |
1234 | 52.0k | vh.field_names.push_back( name ); |
1235 | 52.0k | vh.field_types.push_back( type ); |
1236 | 52.0k | vh.field_descriptions.push_back( description ); |
1237 | 52.0k | vh.field_formats.push_back( format ); |
1238 | 52.0k | vh.field_defaults.push_back( *default_value ); |
1239 | | |
1240 | 52.0k | vh_dirty = true; |
1241 | 52.0k | } |
1242 | | |
1243 | | /************************************************************************/ |
1244 | | /* FlushSegHeaderIfNeeded() */ |
1245 | | /************************************************************************/ |
1246 | | |
1247 | | void CPCIDSKVectorSegment::FlushSegHeaderIfNeeded() |
1248 | 2.06M | { |
1249 | 2.06M | if( vh_dirty ) |
1250 | 1.95k | { |
1251 | 1.95k | vh.WriteFieldDefinitions(); |
1252 | 1.95k | vh_dirty = false; |
1253 | 1.95k | } |
1254 | 2.06M | } |
1255 | | |
1256 | | /************************************************************************/ |
1257 | | /* CreateShape() */ |
1258 | | /************************************************************************/ |
1259 | | |
1260 | | ShapeId CPCIDSKVectorSegment::CreateShape( ShapeId id ) |
1261 | | |
1262 | 685k | { |
1263 | 685k | LoadHeader(); |
1264 | 685k | FlushSegHeaderIfNeeded(); |
1265 | | |
1266 | | /* -------------------------------------------------------------------- */ |
1267 | | /* Make sure we have the last shapeid index page loaded. */ |
1268 | | /* -------------------------------------------------------------------- */ |
1269 | 685k | AccessShapeByIndex( total_shape_count ); |
1270 | | |
1271 | | // if highest_shapeid_used is unset, then look at all Ids |
1272 | 685k | if (highest_shapeid_used == NullShapeId &&!shape_index_ids.empty()) |
1273 | 0 | { |
1274 | 0 | auto it = std::max_element(shape_index_ids.begin(), shape_index_ids.end()); |
1275 | 0 | highest_shapeid_used = *it; |
1276 | 0 | } |
1277 | | |
1278 | | /* -------------------------------------------------------------------- */ |
1279 | | /* Do we need to assign a shapeid? */ |
1280 | | /* -------------------------------------------------------------------- */ |
1281 | 685k | if( id == NullShapeId ) |
1282 | 613k | { |
1283 | 613k | if( highest_shapeid_used == NullShapeId ) |
1284 | 1.35k | id = 0; |
1285 | 611k | else |
1286 | 611k | id = highest_shapeid_used + 1; |
1287 | 613k | } |
1288 | 685k | if( id > highest_shapeid_used ) |
1289 | 685k | highest_shapeid_used = id; |
1290 | 0 | else |
1291 | 0 | { |
1292 | 0 | PopulateShapeIdMap(); |
1293 | 0 | if( shapeid_map.count(id) > 0 ) |
1294 | 0 | { |
1295 | 0 | return ThrowPCIDSKException( 0, "Attempt to create a shape with id '%d', but that already exists.", id ); |
1296 | 0 | } |
1297 | 0 | } |
1298 | | |
1299 | | /* -------------------------------------------------------------------- */ |
1300 | | /* Push this new shape on to our list of shapeids in the */ |
1301 | | /* current page, and mark the page as dirty. */ |
1302 | | /* -------------------------------------------------------------------- */ |
1303 | 685k | shape_index_ids.push_back( id ); |
1304 | 685k | shape_index_record_off.push_back( 0xffffffff ); |
1305 | 685k | shape_index_vertex_off.push_back( 0xffffffff ); |
1306 | 685k | shape_index_page_dirty = true; |
1307 | | |
1308 | 685k | if( shapeid_map_active ) |
1309 | 72.5k | shapeid_map[id] = total_shape_count; |
1310 | | |
1311 | 685k | total_shape_count++; |
1312 | 685k | valid_shape_count++; |
1313 | | |
1314 | 685k | return id; |
1315 | 685k | } |
1316 | | |
1317 | | /************************************************************************/ |
1318 | | /* DeleteShape() */ |
1319 | | /* */ |
1320 | | /* Delete a shape by shapeid. */ |
1321 | | /************************************************************************/ |
1322 | | |
1323 | | void CPCIDSKVectorSegment::DeleteShape( ShapeId id ) |
1324 | | |
1325 | 0 | { |
1326 | 0 | FlushSegHeaderIfNeeded(); |
1327 | 0 | int shape_index = IndexFromShapeId( id ); |
1328 | |
|
1329 | 0 | if( shape_index == -1 ) |
1330 | 0 | return ThrowPCIDSKException( "Attempt to call DeleteShape() on non-existing shape '%d'.", |
1331 | 0 | (int) id ); |
1332 | | |
1333 | | /* ==================================================================== */ |
1334 | | /* Our strategy is to move the last shape in our index down to */ |
1335 | | /* replace the shape that we are deleting. Unfortunately this */ |
1336 | | /* will result in an out of sequence shapeid, but it is hard to */ |
1337 | | /* avoid that without potentially rewriting much of the shape */ |
1338 | | /* index. */ |
1339 | | /* */ |
1340 | | /* Note that the following sequence *does* work for special */ |
1341 | | /* cases like deleting the last shape in the list, or deleting */ |
1342 | | /* a shape on the same page as the last shape. At worst a wee */ |
1343 | | /* bit of extra work is done. */ |
1344 | | /* ==================================================================== */ |
1345 | | |
1346 | | /* -------------------------------------------------------------------- */ |
1347 | | /* Load the page of shapeids containing the last shape in our */ |
1348 | | /* index, capture the last shape's details, and remove it. */ |
1349 | | /* -------------------------------------------------------------------- */ |
1350 | | |
1351 | 0 | uint32 vert_off, rec_off; |
1352 | 0 | ShapeId last_id; |
1353 | |
|
1354 | 0 | AccessShapeByIndex( total_shape_count-1 ); |
1355 | |
|
1356 | 0 | last_id = shape_index_ids[total_shape_count-1-shape_index_start]; |
1357 | 0 | vert_off = shape_index_vertex_off[total_shape_count-1-shape_index_start]; |
1358 | 0 | rec_off = shape_index_record_off[total_shape_count-1-shape_index_start]; |
1359 | | |
1360 | | // We don't actually have to modify this area of the index on disk. |
1361 | | // Some of the stuff at the end just becomes unreferenced when we |
1362 | | // decrement total_shape_count. |
1363 | | |
1364 | | /* -------------------------------------------------------------------- */ |
1365 | | /* Load the page with the shape we are deleting, and put last */ |
1366 | | /* the shapes information over it. */ |
1367 | | /* -------------------------------------------------------------------- */ |
1368 | 0 | AccessShapeByIndex( shape_index ); |
1369 | |
|
1370 | 0 | shape_index_ids[shape_index-shape_index_start] = last_id; |
1371 | 0 | shape_index_vertex_off[shape_index-shape_index_start] = vert_off; |
1372 | 0 | shape_index_record_off[shape_index-shape_index_start] = rec_off; |
1373 | |
|
1374 | 0 | shape_index_page_dirty = true; |
1375 | |
|
1376 | 0 | if( shapeid_map_active ) |
1377 | 0 | shapeid_map.erase( id ); |
1378 | | |
1379 | | // if the highest shape_id is the one that was deleted, |
1380 | | // then reset highest_shapeid_used |
1381 | 0 | if (id == highest_shapeid_used) |
1382 | 0 | highest_shapeid_used = NullShapeId; |
1383 | 0 | total_shape_count--; |
1384 | 0 | valid_shape_count--; |
1385 | 0 | } |
1386 | | |
1387 | | /************************************************************************/ |
1388 | | /* SetVertices() */ |
1389 | | /************************************************************************/ |
1390 | | |
1391 | | void CPCIDSKVectorSegment::SetVertices( ShapeId id, |
1392 | | const std::vector<ShapeVertex>& list ) |
1393 | | |
1394 | 685k | { |
1395 | 685k | FlushSegHeaderIfNeeded(); |
1396 | 685k | int shape_index = IndexFromShapeId( id ); |
1397 | | |
1398 | 685k | if( shape_index == -1 ) |
1399 | 0 | return ThrowPCIDSKException( "Attempt to call SetVertices() on non-existing shape '%d'.", |
1400 | 0 | (int) id ); |
1401 | | |
1402 | 685k | PCIDSKBuffer vbuf( static_cast<int>(list.size()) * 24 + 8 ); |
1403 | | |
1404 | 685k | AccessShapeByIndex( shape_index ); |
1405 | | |
1406 | | /* -------------------------------------------------------------------- */ |
1407 | | /* Is the current space big enough to hold the new vertex set? */ |
1408 | | /* -------------------------------------------------------------------- */ |
1409 | 685k | uint32 vert_off = shape_index_vertex_off[shape_index - shape_index_start]; |
1410 | 685k | uint32 chunk_size = 0; |
1411 | | |
1412 | 685k | if( vert_off != 0xffffffff ) |
1413 | 0 | { |
1414 | 0 | memcpy( &chunk_size, GetData( sec_vert, vert_off, nullptr, 4 ), 4 ); |
1415 | 0 | if( needs_swap ) |
1416 | 0 | SwapData( &chunk_size, 4, 1 ); |
1417 | |
|
1418 | 0 | if( chunk_size < (uint32) vbuf.buffer_size ) |
1419 | 0 | { |
1420 | 0 | vert_off = 0xffffffff; |
1421 | 0 | } |
1422 | 0 | } |
1423 | | |
1424 | | /* -------------------------------------------------------------------- */ |
1425 | | /* Do we need to put this at the end of the section? */ |
1426 | | /* -------------------------------------------------------------------- */ |
1427 | 685k | if( vert_off == 0xffffffff ) |
1428 | 685k | { |
1429 | 685k | vert_off = di[sec_vert].GetSectionEnd(); |
1430 | 685k | chunk_size = vbuf.buffer_size; |
1431 | 685k | } |
1432 | | |
1433 | | /* -------------------------------------------------------------------- */ |
1434 | | /* Format the vertices in a buffer. */ |
1435 | | /* -------------------------------------------------------------------- */ |
1436 | 685k | uint32 vert_count = static_cast<uint32>(list.size()); |
1437 | 685k | unsigned int i; |
1438 | | |
1439 | 685k | memcpy( vbuf.buffer, &chunk_size, 4 ); |
1440 | 685k | memcpy( vbuf.buffer+4, &vert_count, 4 ); |
1441 | 685k | if( needs_swap ) |
1442 | 685k | SwapData( vbuf.buffer, 4, 2 ); |
1443 | | |
1444 | 690k | for( i = 0; i < vert_count; i++ ) |
1445 | 4.14k | { |
1446 | 4.14k | memcpy( vbuf.buffer + 8 + i*24 + 0, &(list[i].x), 8 ); |
1447 | 4.14k | memcpy( vbuf.buffer + 8 + i*24 + 8, &(list[i].y), 8 ); |
1448 | 4.14k | memcpy( vbuf.buffer + 8 + i*24 + 16, &(list[i].z), 8 ); |
1449 | 4.14k | } |
1450 | | |
1451 | 685k | if( needs_swap ) |
1452 | 685k | SwapData( vbuf.buffer + 8, 8, 3*vert_count ); |
1453 | | |
1454 | | /* -------------------------------------------------------------------- */ |
1455 | | /* Write the data into the working buffer. */ |
1456 | | /* -------------------------------------------------------------------- */ |
1457 | 685k | memcpy( GetData( sec_vert, vert_off, nullptr, vbuf.buffer_size, true ), |
1458 | 685k | vbuf.buffer, vbuf.buffer_size ); |
1459 | | |
1460 | | /* -------------------------------------------------------------------- */ |
1461 | | /* Record the offset */ |
1462 | | /* -------------------------------------------------------------------- */ |
1463 | 685k | if( shape_index_vertex_off[shape_index - shape_index_start] != vert_off ) |
1464 | 685k | { |
1465 | 685k | shape_index_vertex_off[shape_index - shape_index_start] = vert_off; |
1466 | 685k | shape_index_page_dirty = true; |
1467 | 685k | } |
1468 | 685k | } |
1469 | | |
1470 | | /************************************************************************/ |
1471 | | /* SetFields() */ |
1472 | | /************************************************************************/ |
1473 | | |
1474 | | void CPCIDSKVectorSegment::SetFields( ShapeId id, |
1475 | | const std::vector<ShapeField>& list_in ) |
1476 | | |
1477 | 681k | { |
1478 | 681k | FlushSegHeaderIfNeeded(); |
1479 | 681k | uint32 i; |
1480 | 681k | int shape_index = IndexFromShapeId( id ); |
1481 | 681k | std::vector<ShapeField> full_list; |
1482 | 681k | const std::vector<ShapeField> *listp = nullptr; |
1483 | | |
1484 | 681k | if( shape_index == -1 ) |
1485 | 0 | return ThrowPCIDSKException( "Attempt to call SetFields() on non-existing shape id '%d'.", |
1486 | 0 | (int) id ); |
1487 | | |
1488 | 681k | if( list_in.size() > vh.field_names.size() ) |
1489 | 0 | { |
1490 | 0 | return ThrowPCIDSKException( |
1491 | 0 | "Attempt to write %d fields to a layer with only %d fields.", |
1492 | 0 | static_cast<int>(list_in.size()), static_cast<int>(vh.field_names.size()) ); |
1493 | 0 | } |
1494 | | |
1495 | 681k | if( list_in.size() < vh.field_names.size() ) |
1496 | 0 | { |
1497 | 0 | full_list = list_in; |
1498 | | |
1499 | | // fill out missing fields in list with defaults. |
1500 | 0 | for( i = static_cast<uint32>(list_in.size()); i < static_cast<uint32>(vh.field_names.size()); i++ ) |
1501 | 0 | full_list[i] = vh.field_defaults[i]; |
1502 | |
|
1503 | 0 | listp = &full_list; |
1504 | 0 | } |
1505 | 681k | else |
1506 | 681k | listp = &list_in; |
1507 | | |
1508 | 681k | AccessShapeByIndex( shape_index ); |
1509 | | |
1510 | | /* -------------------------------------------------------------------- */ |
1511 | | /* Format the fields in the buffer. */ |
1512 | | /* -------------------------------------------------------------------- */ |
1513 | 681k | PCIDSKBuffer fbuf(4); |
1514 | 681k | uint32 offset = 4; |
1515 | | |
1516 | 4.19M | for( i = 0; i < listp->size(); i++ ) |
1517 | 3.51M | offset = WriteField( offset, (*listp)[i], fbuf ); |
1518 | | |
1519 | 681k | fbuf.SetSize( offset ); |
1520 | | |
1521 | | /* -------------------------------------------------------------------- */ |
1522 | | /* Is the current space big enough to hold the new field set? */ |
1523 | | /* -------------------------------------------------------------------- */ |
1524 | 681k | uint32 rec_off = shape_index_record_off[shape_index - shape_index_start]; |
1525 | 681k | uint32 chunk_size = offset; |
1526 | | |
1527 | 681k | if( rec_off != 0xffffffff ) |
1528 | 0 | { |
1529 | 0 | memcpy( &chunk_size, GetData( sec_record, rec_off, nullptr, 4 ), 4 ); |
1530 | 0 | if( needs_swap ) |
1531 | 0 | SwapData( &chunk_size, 4, 1 ); |
1532 | |
|
1533 | 0 | if( chunk_size < (uint32) fbuf.buffer_size ) |
1534 | 0 | { |
1535 | 0 | rec_off = 0xffffffff; |
1536 | 0 | } |
1537 | 0 | } |
1538 | | |
1539 | | /* -------------------------------------------------------------------- */ |
1540 | | /* Do we need to put this at the end of the section? */ |
1541 | | /* -------------------------------------------------------------------- */ |
1542 | 681k | if( rec_off == 0xffffffff ) |
1543 | 681k | { |
1544 | 681k | rec_off = di[sec_record].GetSectionEnd(); |
1545 | 681k | chunk_size = fbuf.buffer_size; |
1546 | 681k | } |
1547 | | |
1548 | | /* -------------------------------------------------------------------- */ |
1549 | | /* Set the chunk size, and number of fields. */ |
1550 | | /* -------------------------------------------------------------------- */ |
1551 | 681k | memcpy( fbuf.buffer + 0, &chunk_size, 4 ); |
1552 | | |
1553 | 681k | if( needs_swap ) |
1554 | 681k | SwapData( fbuf.buffer, 4, 1 ); |
1555 | | |
1556 | | /* -------------------------------------------------------------------- */ |
1557 | | /* Write the data into the working buffer. */ |
1558 | | /* -------------------------------------------------------------------- */ |
1559 | 681k | memcpy( GetData( sec_record, rec_off, nullptr, fbuf.buffer_size, true ), |
1560 | 681k | fbuf.buffer, fbuf.buffer_size ); |
1561 | | |
1562 | | /* -------------------------------------------------------------------- */ |
1563 | | /* Record the offset */ |
1564 | | /* -------------------------------------------------------------------- */ |
1565 | 681k | if( shape_index_record_off[shape_index - shape_index_start] != rec_off ) |
1566 | 681k | { |
1567 | 681k | shape_index_record_off[shape_index - shape_index_start] = rec_off; |
1568 | 681k | shape_index_page_dirty = true; |
1569 | 681k | } |
1570 | 681k | } |
1571 | | |
1572 | | /************************************************************************/ |
1573 | | /* FlushLoadedShapeIndex() */ |
1574 | | /************************************************************************/ |
1575 | | |
1576 | | void CPCIDSKVectorSegment::FlushLoadedShapeIndex() |
1577 | | |
1578 | 14.2k | { |
1579 | 14.2k | if( !shape_index_page_dirty ) |
1580 | 12.2k | return; |
1581 | | |
1582 | 1.97k | uint32 offset = vh.ShapeIndexPrepare( total_shape_count * 12 + 4 ); |
1583 | | |
1584 | 1.97k | PCIDSKBuffer write_buffer( shapeid_page_size * 12 ); |
1585 | | |
1586 | | // Update the count field. |
1587 | 1.97k | memcpy( write_buffer.buffer, &total_shape_count, 4 ); |
1588 | 1.97k | if( needs_swap ) |
1589 | 1.97k | SwapData( write_buffer.buffer, 4, 1 ); |
1590 | 1.97k | WriteToFile( write_buffer.buffer, offset, 4 ); |
1591 | | |
1592 | | // Write out the page of shapeid information. |
1593 | 1.97k | unsigned int i; |
1594 | 687k | for( i = 0; i < shape_index_ids.size(); i++ ) |
1595 | 685k | { |
1596 | 685k | memcpy( write_buffer.buffer + 12*i, |
1597 | 685k | &(shape_index_ids[i]), 4 ); |
1598 | 685k | memcpy( write_buffer.buffer + 12*i + 4, |
1599 | 685k | &(shape_index_vertex_off[i]), 4 ); |
1600 | 685k | memcpy( write_buffer.buffer + 12*i + 8, |
1601 | 685k | &(shape_index_record_off[i]), 4 ); |
1602 | 685k | } |
1603 | | |
1604 | 1.97k | if( needs_swap ) |
1605 | 1.97k | SwapData( write_buffer.buffer, 4, static_cast<int>(shape_index_ids.size()) * 3 ); |
1606 | | |
1607 | 1.97k | WriteToFile( write_buffer.buffer, |
1608 | 1.97k | offset + 4 + shape_index_start * 12, |
1609 | 1.97k | 12 * shape_index_ids.size() ); |
1610 | | |
1611 | | // invalidate the raw buffer. |
1612 | 1.97k | raw_loaded_data.buffer_size = 0; |
1613 | | |
1614 | | |
1615 | 1.97k | shape_index_page_dirty = false; |
1616 | 1.97k | } |
1617 | | |