1
/******************************************************************************
3
* Purpose: Implementation of the VecSegIndex class.
5
* This class is used to manage a vector segment data block index. There
6
* will be two instances created, one for the record data (sec_record) and
7
* one for the vertices (sec_vert). This class is exclusively a private
8
* helper class for VecSegHeader.
10
******************************************************************************
12
* PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
14
* Permission is hereby granted, free of charge, to any person obtaining a
15
* copy of this software and associated documentation files (the "Software"),
16
* to deal in the Software without restriction, including without limitation
17
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
18
* and/or sell copies of the Software, and to permit persons to whom the
19
* Software is furnished to do so, subject to the following conditions:
21
* The above copyright notice and this permission notice shall be included
22
* in all copies or substantial portions of the Software.
24
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30
* DEALINGS IN THE SOFTWARE.
31
****************************************************************************/
34
#include "core/pcidsk_utils.h"
35
#include "segment/cpcidskvectorsegment.h"
40
using namespace PCIDSK;
42
/* -------------------------------------------------------------------- */
43
/* Size of a block in the record/vertice block tables. This is */
44
/* determined by the PCIDSK format and may not be changed. */
45
/* -------------------------------------------------------------------- */
46
static const int block_page_size = 8192;
48
/************************************************************************/
49
/* VecSegDataIndex() */
50
/************************************************************************/
52
VecSegDataIndex::VecSegDataIndex()
55
block_initialized = false;
60
/************************************************************************/
61
/* ~VecSegDataIndex() */
62
/************************************************************************/
64
VecSegDataIndex::~VecSegDataIndex()
69
/************************************************************************/
71
/************************************************************************/
73
void VecSegDataIndex::Initialize( CPCIDSKVectorSegment *vs, int section )
76
this->section = section;
79
if( section == sec_vert )
80
offset_on_disk_within_section = 0;
82
offset_on_disk_within_section = vs->di[sec_vert].SerializedSize();
84
uint32 offset = offset_on_disk_within_section
85
+ vs->vh.section_offsets[hsec_shape];
87
memcpy( &block_count, vs->GetData(sec_raw,offset,NULL,4), 4);
88
memcpy( &bytes, vs->GetData(sec_raw,offset+4,NULL,4), 4);
90
bool needs_swap = !BigEndianSystem();
94
SwapData( &block_count, 4, 1 );
95
SwapData( &bytes, 4, 1 );
98
size_on_disk = block_count * 4 + 8;
101
/************************************************************************/
102
/* SerializedSize() */
103
/************************************************************************/
105
uint32 VecSegDataIndex::SerializedSize()
108
return 8 + 4 * block_count;
111
/************************************************************************/
112
/* GetBlockIndex() */
113
/************************************************************************/
115
const std::vector<uint32> *VecSegDataIndex::GetIndex()
118
/* -------------------------------------------------------------------- */
119
/* Load block map if needed. */
120
/* -------------------------------------------------------------------- */
121
if( !block_initialized )
123
bool needs_swap = !BigEndianSystem();
125
block_index.resize( block_count );
126
if( block_count > 0 )
128
vs->ReadFromFile( &(block_index[0]),
129
offset_on_disk_within_section
130
+ vs->vh.section_offsets[hsec_shape] + 8,
134
SwapData( &(block_index[0]), 4, block_count );
137
block_initialized = true;
143
/************************************************************************/
145
/************************************************************************/
147
void VecSegDataIndex::Flush()
153
GetIndex(); // force loading if not already loaded!
155
PCIDSKBuffer wbuf( SerializedSize() );
157
memcpy( wbuf.buffer + 0, &block_count, 4 );
158
memcpy( wbuf.buffer + 4, &bytes, 4 );
159
memcpy( wbuf.buffer + 8, &(block_index[0]), 4*block_count );
161
bool needs_swap = !BigEndianSystem();
164
SwapData( wbuf.buffer, 4, block_count+2 );
166
// Make sure this section of the header is large enough.
167
int32 shift = (int32) wbuf.buffer_size - (int32) size_on_disk;
171
uint32 old_section_size = vs->vh.section_sizes[hsec_shape];
173
// fprintf( stderr, "Shifting section %d by %d bytes.\n",
176
vs->vh.GrowSection( hsec_shape, old_section_size + shift );
178
if( section == sec_vert )
180
// move record block index and shape index.
181
vs->MoveData( vs->vh.section_offsets[hsec_shape]
182
+ vs->di[sec_vert].size_on_disk,
183
vs->vh.section_offsets[hsec_shape]
184
+ vs->di[sec_vert].size_on_disk + shift,
185
old_section_size - size_on_disk );
189
// only move shape index.
190
vs->MoveData( vs->vh.section_offsets[hsec_shape]
191
+ vs->di[sec_vert].size_on_disk
192
+ vs->di[sec_record].size_on_disk,
193
vs->vh.section_offsets[hsec_shape]
194
+ vs->di[sec_vert].size_on_disk
195
+ vs->di[sec_record].size_on_disk
198
- vs->di[sec_vert].size_on_disk
199
- vs->di[sec_record].size_on_disk );
202
if( section == sec_vert )
203
vs->di[sec_record].offset_on_disk_within_section += shift;
206
// Actually write to disk.
207
vs->WriteToFile( wbuf.buffer,
208
offset_on_disk_within_section
209
+ vs->vh.section_offsets[hsec_shape],
212
size_on_disk = wbuf.buffer_size;
216
/************************************************************************/
217
/* GetSectionEnd() */
218
/************************************************************************/
220
uint32 VecSegDataIndex::GetSectionEnd()
226
/************************************************************************/
227
/* SetSectionEnd() */
228
/************************************************************************/
230
void VecSegDataIndex::SetSectionEnd( uint32 new_end )
233
// should we keep track of the need to write this back to disk?
237
/************************************************************************/
238
/* AddBlockToIndex() */
239
/************************************************************************/
241
void VecSegDataIndex::AddBlockToIndex( uint32 block )
244
GetIndex(); // force loading.
246
block_index.push_back( block );
251
/************************************************************************/
254
/* This method is primarily used to mark the need to write the */
255
/* index when the location changes. */
256
/************************************************************************/
258
void VecSegDataIndex::SetDirty()
264
/************************************************************************/
265
/* VacateBlockRange() */
267
/* Move any blocks in the indicated block range to the end of */
268
/* the segment to make space for a growing header. */
269
/************************************************************************/
271
void VecSegDataIndex::VacateBlockRange( uint32 start, uint32 count )
274
GetIndex(); // make sure loaded.
277
uint32 next_block = (uint32) (vs->GetContentSize() / block_page_size);
279
for( i = 0; i < block_count; i++ )
281
if( block_index[i] >= start && block_index[i] < start+count )
283
vs->MoveData( block_index[i] * block_page_size,
284
next_block * block_page_size,
286
block_index[i] = next_block;