1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the SysVirtualFile class.
4 : *
5 : * This class is used to manage access to a single virtual file stored in
6 : * SysBData segments based on a block map stored in the SysBMDir segment
7 : * (and managed by SysBlockMap class).
8 : *
9 : * The virtual files are allocated in 8K chunks (block_size) in segments.
10 : * To minimize IO requests, other overhead, we keep one such 8K block in
11 : * our working cache for the virtual file stream.
12 : *
13 : * This class is primarily used by the CTiledChannel class for access to
14 : * tiled images.
15 : *
16 : ******************************************************************************
17 : * Copyright (c) 2009
18 : * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining a
21 : * copy of this software and associated documentation files (the "Software"),
22 : * to deal in the Software without restriction, including without limitation
23 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
24 : * and/or sell copies of the Software, and to permit persons to whom the
25 : * Software is furnished to do so, subject to the following conditions:
26 : *
27 : * The above copyright notice and this permission notice shall be included
28 : * in all copies or substantial portions of the Software.
29 : *
30 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
31 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
33 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
35 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
36 : * DEALINGS IN THE SOFTWARE.
37 : ****************************************************************************/
38 : #include "pcidsk_config.h"
39 : #include "pcidsk_types.h"
40 : #include "pcidsk_buffer.h"
41 : #include "pcidsk_exception.h"
42 : #include "core/sysvirtualfile.h"
43 : #include "core/cpcidskfile.h"
44 : #include "segment/sysblockmap.h"
45 : #include <cassert>
46 : #include <cstring>
47 :
48 : using namespace PCIDSK;
49 :
50 :
51 : const int SysVirtualFile::block_size = SYSVIRTUALFILE_BLOCKSIZE;
52 :
53 : /************************************************************************/
54 : /* SysVirtualFile() */
55 : /************************************************************************/
56 :
57 3 : SysVirtualFile::SysVirtualFile( CPCIDSKFile *file, int start_block,
58 : uint64 image_length,
59 : PCIDSKBuffer &block_map_data,
60 : SysBlockMap *sysblockmap,
61 3 : int image_index )
62 :
63 : {
64 3 : file_length = image_length;
65 3 : this->file = file;
66 3 : this->sysblockmap = sysblockmap;
67 3 : this->image_index = image_index;
68 :
69 3 : loaded_block = -1;
70 3 : loaded_block_dirty = false;
71 :
72 3 : last_bm_index = -1;
73 :
74 3 : int next_block = start_block;
75 :
76 : // perhaps we should defer all this work till the first request is made?
77 9 : while( next_block != -1 )
78 : {
79 3 : int offset = 512 + next_block * 28;
80 :
81 3 : block_segment.push_back( block_map_data.GetInt( offset+0, 4 ) );
82 3 : block_index.push_back( block_map_data.GetInt( offset+4, 8 ) );
83 :
84 3 : last_bm_index = next_block;
85 3 : next_block = block_map_data.GetInt( offset + 20, 8 );
86 : }
87 :
88 3 : assert( block_index.size() * block_size >= file_length );
89 3 : }
90 :
91 : /************************************************************************/
92 : /* ~SysVirtualFile() */
93 : /************************************************************************/
94 :
95 3 : SysVirtualFile::~SysVirtualFile()
96 :
97 : {
98 3 : if( loaded_block_dirty )
99 : {
100 : PCIDSKSegment *data_seg_obj =
101 0 : file->GetSegment( block_segment[loaded_block] );
102 :
103 : data_seg_obj->WriteToFile( block_data,
104 : block_size * (uint64) block_index[loaded_block],
105 0 : block_size );
106 0 : loaded_block_dirty = false;
107 : }
108 3 : }
109 :
110 :
111 : /************************************************************************/
112 : /* WriteToFile() */
113 : /************************************************************************/
114 :
115 : void
116 0 : SysVirtualFile::WriteToFile( const void *buffer, uint64 offset, uint64 size )
117 :
118 : {
119 0 : uint64 buffer_offset = 0;
120 :
121 0 : while( buffer_offset < size )
122 : {
123 0 : int request_block = (int) ((offset + buffer_offset) / block_size);
124 0 : int offset_in_block = (int) ((offset + buffer_offset) % block_size);
125 : int amount_to_copy;
126 :
127 0 : LoadBlock( request_block );
128 :
129 0 : amount_to_copy = block_size - offset_in_block;
130 0 : if( amount_to_copy > (int) (size - buffer_offset) )
131 0 : amount_to_copy = (int) (size - buffer_offset);
132 :
133 : memcpy( block_data + offset_in_block,
134 : ((uint8 *) buffer) + buffer_offset,
135 0 : amount_to_copy );
136 :
137 0 : loaded_block_dirty = true;
138 :
139 0 : buffer_offset += amount_to_copy;
140 : }
141 :
142 0 : if( offset+size > file_length )
143 : {
144 0 : file_length = offset+size;
145 0 : sysblockmap->SetVirtualFileSize( image_index, file_length );
146 : }
147 0 : }
148 :
149 : /************************************************************************/
150 : /* ReadFromFile() */
151 : /************************************************************************/
152 :
153 7 : void SysVirtualFile::ReadFromFile( void *buffer, uint64 offset, uint64 size )
154 :
155 : {
156 7 : uint64 buffer_offset = 0;
157 :
158 21 : while( buffer_offset < size )
159 : {
160 7 : int request_block = (int) ((offset + buffer_offset) / block_size);
161 7 : int offset_in_block = (int) ((offset + buffer_offset) % block_size);
162 : int amount_to_copy;
163 :
164 7 : LoadBlock( request_block );
165 :
166 7 : amount_to_copy = block_size - offset_in_block;
167 7 : if( amount_to_copy > (int) (size - buffer_offset) )
168 7 : amount_to_copy = (int) (size - buffer_offset);
169 :
170 : memcpy( ((uint8 *) buffer) + buffer_offset,
171 7 : block_data + offset_in_block, amount_to_copy );
172 :
173 7 : buffer_offset += amount_to_copy;
174 : }
175 7 : }
176 :
177 : /************************************************************************/
178 : /* LoadBlock() */
179 : /************************************************************************/
180 :
181 7 : void SysVirtualFile::LoadBlock( int requested_block )
182 :
183 : {
184 : /* -------------------------------------------------------------------- */
185 : /* Do we already have this block? */
186 : /* -------------------------------------------------------------------- */
187 7 : if( requested_block == loaded_block )
188 4 : return;
189 :
190 : /* -------------------------------------------------------------------- */
191 : /* Do we need to grow the virtual file by one block? */
192 : /* -------------------------------------------------------------------- */
193 3 : if( requested_block == (int) block_index.size() )
194 : {
195 : int new_seg;
196 :
197 : block_index.push_back(
198 : sysblockmap->GrowVirtualFile( image_index,
199 0 : last_bm_index, new_seg ) );
200 0 : block_segment.push_back( new_seg );
201 : }
202 :
203 : /* -------------------------------------------------------------------- */
204 : /* Does this block exist in the virtual file? */
205 : /* -------------------------------------------------------------------- */
206 3 : if( requested_block < 0 || requested_block >= (int) block_index.size() )
207 : ThrowPCIDSKException( "SysVirtualFile::LoadBlock(%d) - block out of range.",
208 0 : requested_block );
209 :
210 : /* -------------------------------------------------------------------- */
211 : /* Do we have a dirty block loaded that needs to be saved? */
212 : /* -------------------------------------------------------------------- */
213 3 : if( loaded_block_dirty )
214 : {
215 : PCIDSKSegment *data_seg_obj =
216 0 : file->GetSegment( block_segment[loaded_block] );
217 :
218 : data_seg_obj->WriteToFile( block_data,
219 : block_size * (uint64) block_index[loaded_block],
220 0 : block_size );
221 0 : loaded_block_dirty = false;
222 : }
223 :
224 : /* -------------------------------------------------------------------- */
225 : /* Load the requested block. */
226 : /* -------------------------------------------------------------------- */
227 : PCIDSKSegment *data_seg_obj =
228 3 : file->GetSegment( block_segment[requested_block] );
229 :
230 : data_seg_obj->ReadFromFile( block_data,
231 : block_size * (uint64) block_index[requested_block],
232 3 : block_size );
233 :
234 3 : loaded_block = requested_block;
235 3 : loaded_block_dirty = false;
236 : }
237 :
|