1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the VecSegIndex class.
4 : *
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.
9 : *
10 : ******************************************************************************
11 : * Copyright (c) 2010
12 : * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
13 : *
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:
20 : *
21 : * The above copyright notice and this permission notice shall be included
22 : * in all copies or substantial portions of the Software.
23 : *
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 : ****************************************************************************/
32 :
33 : #include "pcidsk.h"
34 : #include "core/pcidsk_utils.h"
35 : #include "segment/cpcidskvectorsegment.h"
36 : #include <cassert>
37 : #include <cstring>
38 : #include <cstdio>
39 :
40 : using namespace PCIDSK;
41 :
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;
47 :
48 : /************************************************************************/
49 : /* VecSegDataIndex() */
50 : /************************************************************************/
51 :
52 112 : VecSegDataIndex::VecSegDataIndex()
53 :
54 : {
55 112 : block_initialized = false;
56 112 : vs = NULL;
57 112 : dirty = false;
58 112 : }
59 :
60 : /************************************************************************/
61 : /* ~VecSegDataIndex() */
62 : /************************************************************************/
63 :
64 112 : VecSegDataIndex::~VecSegDataIndex()
65 :
66 : {
67 112 : }
68 :
69 : /************************************************************************/
70 : /* Initialize() */
71 : /************************************************************************/
72 :
73 108 : void VecSegDataIndex::Initialize( CPCIDSKVectorSegment *vs, int section )
74 :
75 : {
76 108 : this->section = section;
77 108 : this->vs = vs;
78 :
79 108 : if( section == sec_vert )
80 54 : offset_on_disk_within_section = 0;
81 : else
82 54 : offset_on_disk_within_section = vs->di[sec_vert].SerializedSize();
83 :
84 : uint32 offset = offset_on_disk_within_section
85 108 : + vs->vh.section_offsets[hsec_shape];
86 :
87 108 : memcpy( &block_count, vs->GetData(sec_raw,offset,NULL,4), 4);
88 108 : memcpy( &bytes, vs->GetData(sec_raw,offset+4,NULL,4), 4);
89 :
90 108 : bool needs_swap = !BigEndianSystem();
91 :
92 108 : if( needs_swap )
93 : {
94 108 : SwapData( &block_count, 4, 1 );
95 108 : SwapData( &bytes, 4, 1 );
96 : }
97 :
98 108 : size_on_disk = block_count * 4 + 8;
99 108 : }
100 :
101 : /************************************************************************/
102 : /* SerializedSize() */
103 : /************************************************************************/
104 :
105 176 : uint32 VecSegDataIndex::SerializedSize()
106 :
107 : {
108 176 : return 8 + 4 * block_count;
109 : }
110 :
111 : /************************************************************************/
112 : /* GetBlockIndex() */
113 : /************************************************************************/
114 :
115 2038 : const std::vector<uint32> *VecSegDataIndex::GetIndex()
116 :
117 : {
118 : /* -------------------------------------------------------------------- */
119 : /* Load block map if needed. */
120 : /* -------------------------------------------------------------------- */
121 2038 : if( !block_initialized )
122 : {
123 50 : bool needs_swap = !BigEndianSystem();
124 :
125 50 : block_index.resize( block_count );
126 50 : if( block_count > 0 )
127 : {
128 : vs->ReadFromFile( &(block_index[0]),
129 : offset_on_disk_within_section
130 36 : + vs->vh.section_offsets[hsec_shape] + 8,
131 72 : 4 * block_count );
132 :
133 36 : if( needs_swap )
134 36 : SwapData( &(block_index[0]), 4, block_count );
135 : }
136 :
137 50 : block_initialized = true;
138 : }
139 :
140 2038 : return &block_index;
141 : }
142 :
143 : /************************************************************************/
144 : /* Flush() */
145 : /************************************************************************/
146 :
147 160 : void VecSegDataIndex::Flush()
148 :
149 : {
150 160 : if( !dirty )
151 146 : return;
152 :
153 14 : GetIndex(); // force loading if not already loaded!
154 :
155 14 : PCIDSKBuffer wbuf( SerializedSize() );
156 :
157 14 : memcpy( wbuf.buffer + 0, &block_count, 4 );
158 14 : memcpy( wbuf.buffer + 4, &bytes, 4 );
159 14 : memcpy( wbuf.buffer + 8, &(block_index[0]), 4*block_count );
160 :
161 14 : bool needs_swap = !BigEndianSystem();
162 :
163 14 : if( needs_swap )
164 14 : SwapData( wbuf.buffer, 4, block_count+2 );
165 :
166 : // Make sure this section of the header is large enough.
167 14 : int32 shift = (int32) wbuf.buffer_size - (int32) size_on_disk;
168 :
169 14 : if( shift != 0 )
170 : {
171 14 : uint32 old_section_size = vs->vh.section_sizes[hsec_shape];
172 :
173 : // fprintf( stderr, "Shifting section %d by %d bytes.\n",
174 : // section, shift );
175 :
176 14 : vs->vh.GrowSection( hsec_shape, old_section_size + shift );
177 :
178 14 : if( section == sec_vert )
179 : {
180 : // move record block index and shape index.
181 12 : vs->MoveData( vs->vh.section_offsets[hsec_shape]
182 : + vs->di[sec_vert].size_on_disk,
183 12 : vs->vh.section_offsets[hsec_shape]
184 : + vs->di[sec_vert].size_on_disk + shift,
185 36 : old_section_size - size_on_disk );
186 : }
187 : else
188 : {
189 : // only move shape index.
190 2 : 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 2 : vs->vh.section_offsets[hsec_shape]
194 : + vs->di[sec_vert].size_on_disk
195 : + vs->di[sec_record].size_on_disk
196 : + shift,
197 : old_section_size
198 : - vs->di[sec_vert].size_on_disk
199 6 : - vs->di[sec_record].size_on_disk );
200 : }
201 :
202 14 : if( section == sec_vert )
203 12 : vs->di[sec_record].offset_on_disk_within_section += shift;
204 : }
205 :
206 : // Actually write to disk.
207 : vs->WriteToFile( wbuf.buffer,
208 : offset_on_disk_within_section
209 14 : + vs->vh.section_offsets[hsec_shape],
210 28 : wbuf.buffer_size );
211 :
212 14 : size_on_disk = wbuf.buffer_size;
213 14 : dirty = false;
214 : }
215 :
216 : /************************************************************************/
217 : /* GetSectionEnd() */
218 : /************************************************************************/
219 :
220 276414 : uint32 VecSegDataIndex::GetSectionEnd()
221 :
222 : {
223 276414 : return bytes;
224 : }
225 :
226 : /************************************************************************/
227 : /* SetSectionEnd() */
228 : /************************************************************************/
229 :
230 18 : void VecSegDataIndex::SetSectionEnd( uint32 new_end )
231 :
232 : {
233 : // should we keep track of the need to write this back to disk?
234 18 : bytes = new_end;
235 18 : }
236 :
237 : /************************************************************************/
238 : /* AddBlockToIndex() */
239 : /************************************************************************/
240 :
241 14 : void VecSegDataIndex::AddBlockToIndex( uint32 block )
242 :
243 : {
244 14 : GetIndex(); // force loading.
245 :
246 14 : block_index.push_back( block );
247 14 : block_count++;
248 14 : dirty = true;
249 14 : }
250 :
251 : /************************************************************************/
252 : /* SetDirty() */
253 : /* */
254 : /* This method is primarily used to mark the need to write the */
255 : /* index when the location changes. */
256 : /************************************************************************/
257 :
258 0 : void VecSegDataIndex::SetDirty()
259 :
260 : {
261 0 : dirty = true;
262 0 : }
263 :
264 : /************************************************************************/
265 : /* VacateBlockRange() */
266 : /* */
267 : /* Move any blocks in the indicated block range to the end of */
268 : /* the segment to make space for a growing header. */
269 : /************************************************************************/
270 :
271 0 : void VecSegDataIndex::VacateBlockRange( uint32 start, uint32 count )
272 :
273 : {
274 0 : GetIndex(); // make sure loaded.
275 :
276 : unsigned int i;
277 0 : uint32 next_block = (uint32) (vs->GetContentSize() / block_page_size);
278 :
279 0 : for( i = 0; i < block_count; i++ )
280 : {
281 0 : if( block_index[i] >= start && block_index[i] < start+count )
282 : {
283 : vs->MoveData( block_index[i] * block_page_size,
284 : next_block * block_page_size,
285 0 : block_page_size );
286 0 : block_index[i] = next_block;
287 0 : dirty = true;
288 0 : next_block++;
289 : }
290 : }
291 0 : }
|