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