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 56 : VecSegDataIndex::VecSegDataIndex()
53 :
54 : {
55 56 : block_initialized = false;
56 56 : vs = NULL;
57 56 : dirty = false;
58 56 : }
59 :
60 : /************************************************************************/
61 : /* ~VecSegDataIndex() */
62 : /************************************************************************/
63 :
64 56 : VecSegDataIndex::~VecSegDataIndex()
65 :
66 : {
67 56 : }
68 :
69 : /************************************************************************/
70 : /* Initialize() */
71 : /************************************************************************/
72 :
73 54 : void VecSegDataIndex::Initialize( CPCIDSKVectorSegment *vs, int section )
74 :
75 : {
76 54 : this->section = section;
77 54 : this->vs = vs;
78 :
79 54 : if( section == sec_vert )
80 27 : offset_on_disk_within_section = 0;
81 : else
82 27 : offset_on_disk_within_section = vs->di[sec_vert].SerializedSize();
83 :
84 : uint32 offset = offset_on_disk_within_section
85 54 : + vs->vh.section_offsets[hsec_shape];
86 :
87 54 : memcpy( &block_count, vs->GetData(sec_raw,offset,NULL,4), 4);
88 54 : memcpy( &bytes, vs->GetData(sec_raw,offset+4,NULL,4), 4);
89 :
90 54 : bool needs_swap = !BigEndianSystem();
91 :
92 54 : if( needs_swap )
93 : {
94 54 : SwapData( &block_count, 4, 1 );
95 54 : SwapData( &bytes, 4, 1 );
96 : }
97 :
98 54 : size_on_disk = block_count * 4 + 8;
99 54 : }
100 :
101 : /************************************************************************/
102 : /* SerializedSize() */
103 : /************************************************************************/
104 :
105 88 : uint32 VecSegDataIndex::SerializedSize()
106 :
107 : {
108 88 : return 8 + 4 * block_count;
109 : }
110 :
111 : /************************************************************************/
112 : /* GetBlockIndex() */
113 : /************************************************************************/
114 :
115 1215 : const std::vector<uint32> *VecSegDataIndex::GetIndex()
116 :
117 : {
118 : /* -------------------------------------------------------------------- */
119 : /* Load block map if needed. */
120 : /* -------------------------------------------------------------------- */
121 1215 : if( !block_initialized )
122 : {
123 25 : bool needs_swap = !BigEndianSystem();
124 :
125 25 : block_index.resize( block_count );
126 25 : if( block_count > 0 )
127 : {
128 : vs->ReadFromFile( &(block_index[0]),
129 : offset_on_disk_within_section
130 18 : + vs->vh.section_offsets[hsec_shape] + 8,
131 36 : 4 * block_count );
132 :
133 18 : if( needs_swap )
134 18 : SwapData( &(block_index[0]), 4, block_count );
135 : }
136 :
137 25 : block_initialized = true;
138 : }
139 :
140 1215 : return &block_index;
141 : }
142 :
143 : /************************************************************************/
144 : /* Flush() */
145 : /************************************************************************/
146 :
147 80 : void VecSegDataIndex::Flush()
148 :
149 : {
150 80 : if( !dirty )
151 73 : return;
152 :
153 7 : GetIndex(); // force loading if not already loaded!
154 :
155 7 : PCIDSKBuffer wbuf( SerializedSize() );
156 :
157 7 : memcpy( wbuf.buffer + 0, &block_count, 4 );
158 7 : memcpy( wbuf.buffer + 4, &bytes, 4 );
159 7 : memcpy( wbuf.buffer + 8, &(block_index[0]), 4*block_count );
160 :
161 7 : bool needs_swap = !BigEndianSystem();
162 :
163 7 : if( needs_swap )
164 7 : SwapData( wbuf.buffer, 4, block_count+2 );
165 :
166 : // Make sure this section of the header is large enough.
167 7 : int32 shift = (int32) wbuf.buffer_size - (int32) size_on_disk;
168 :
169 7 : if( shift != 0 )
170 : {
171 7 : 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 7 : vs->vh.GrowSection( hsec_shape, old_section_size + shift );
177 :
178 7 : if( section == sec_vert )
179 : {
180 : // move record block index and shape index.
181 6 : vs->MoveData( vs->vh.section_offsets[hsec_shape]
182 : + vs->di[sec_vert].size_on_disk,
183 6 : vs->vh.section_offsets[hsec_shape]
184 : + vs->di[sec_vert].size_on_disk + shift,
185 18 : old_section_size - size_on_disk );
186 : }
187 : else
188 : {
189 : // only move shape index.
190 1 : 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 1 : 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 3 : - vs->di[sec_record].size_on_disk );
200 : }
201 :
202 7 : if( section == sec_vert )
203 6 : 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 7 : + vs->vh.section_offsets[hsec_shape],
210 14 : wbuf.buffer_size );
211 :
212 7 : size_on_disk = wbuf.buffer_size;
213 7 : dirty = false;
214 : }
215 :
216 : /************************************************************************/
217 : /* GetSectionEnd() */
218 : /************************************************************************/
219 :
220 168601 : uint32 VecSegDataIndex::GetSectionEnd()
221 :
222 : {
223 168601 : return bytes;
224 : }
225 :
226 : /************************************************************************/
227 : /* SetSectionEnd() */
228 : /************************************************************************/
229 :
230 9 : void VecSegDataIndex::SetSectionEnd( uint32 new_end )
231 :
232 : {
233 : // should we keep track of the need to write this back to disk?
234 9 : bytes = new_end;
235 9 : }
236 :
237 : /************************************************************************/
238 : /* AddBlockToIndex() */
239 : /************************************************************************/
240 :
241 7 : void VecSegDataIndex::AddBlockToIndex( uint32 block )
242 :
243 : {
244 7 : GetIndex(); // force loading.
245 :
246 7 : block_index.push_back( block );
247 7 : block_count++;
248 7 : dirty = true;
249 7 : }
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 : }
|