~ubuntu-branches/debian/sid/gdal/sid

« back to all changes in this revision

Viewing changes to frmts/pcidsk/sdk/segment/sysblockmap.cpp

  • Committer: Package Import Robot
  • Author(s): Francesco Paolo Lovergine
  • Date: 2012-05-07 15:04:42 UTC
  • mfrom: (5.5.16 experimental)
  • Revision ID: package-import@ubuntu.com-20120507150442-2eks97loeh6rq005
Tags: 1.9.0-1
* Ready for sid, starting transition.
* All symfiles updated to latest builds.
* Added dh_numpy call in debian/rules to depend on numpy ABI.
* Policy bumped to 3.9.3, no changes required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
#include <cassert>
43
43
#include <vector>
44
44
#include <cstring>
 
45
#include <cstdlib>
45
46
 
46
47
using namespace PCIDSK;
47
48
 
54
55
        : CPCIDSKSegment( file, segment, segment_pointer )
55
56
 
56
57
{
57
 
    loaded = false;
 
58
    partial_loaded = false;
 
59
    full_loaded = false;
58
60
    dirty = false;
59
61
    growing_segment = 0;
60
62
}
103
105
}
104
106
 
105
107
/************************************************************************/
106
 
/*                                Load()                                */
 
108
/*                            PartialLoad()                             */
 
109
/*                                                                      */
 
110
/*      Load the header and some per-layer information.                 */
107
111
/************************************************************************/
108
112
 
109
 
void SysBlockMap::Load()
 
113
void SysBlockMap::PartialLoad()
110
114
 
111
115
{
112
 
    if( loaded )
 
116
    if( partial_loaded )
113
117
        return;
114
118
 
115
 
    // TODO: this should likely be protected by a mutex. 
116
 
 
117
 
/* -------------------------------------------------------------------- */
118
 
/*      Load the segment contents into a buffer.                        */
119
 
/* -------------------------------------------------------------------- */
120
 
    seg_data.SetSize( (int) (data_size - 1024) );
121
 
 
122
 
    ReadFromFile( seg_data.buffer, 0, data_size - 1024 );
123
 
 
124
 
    if( strncmp(seg_data.buffer,"VERSION",7) != 0 )
125
 
        ThrowPCIDSKException( "SysBlockMap::Load() - block map corrupt." );
126
 
 
127
 
    if( seg_data.GetInt( 7, 3 ) != 1 )
128
 
        ThrowPCIDSKException( "SysBlockMap::Load() - unsupported version." );
 
119
//    printf( "<PartialLoad>" );
 
120
//    fflush( stdout );
 
121
 
 
122
/* -------------------------------------------------------------------- */
 
123
/*      Load the 512 byte count section of the blockmap.                */
 
124
/* -------------------------------------------------------------------- */
 
125
    PCIDSKBuffer count_data;
 
126
 
 
127
    count_data.SetSize( 512 );
 
128
    ReadFromFile( count_data.buffer, 0, 512 );
 
129
 
 
130
    if( strncmp(count_data.buffer,"VERSION",7) != 0 )
 
131
        ThrowPCIDSKException( "SysBlockMap::PartialLoad() - block map corrupt." );
 
132
 
 
133
    if( count_data.GetInt( 7, 3 ) != 1 )
 
134
        ThrowPCIDSKException( "SysBlockMap::PartialLoad() - unsupported version." );
129
135
 
130
136
/* -------------------------------------------------------------------- */
131
137
/*      Establish our SysVirtualFile array based on the number of       */
132
138
/*      images listed in the image list.                                */
133
139
/* -------------------------------------------------------------------- */
134
 
    int layer_count = seg_data.GetInt( 10, 8 );
135
 
 
136
 
    block_count = seg_data.GetInt( 18, 8 );
137
 
    first_free_block = seg_data.GetInt( 26, 8 );
 
140
    int layer_count = count_data.GetInt( 10, 8 );
138
141
 
139
142
    virtual_files.resize( layer_count );
140
143
 
141
 
    block_map_offset = 512;
142
 
    layer_list_offset = block_map_offset + 28 * block_count;
143
 
 
144
 
    loaded = true;
 
144
    block_count = count_data.GetInt( 18, 8 );
 
145
    first_free_block = count_data.GetInt( 26, 8 );
 
146
 
 
147
/* -------------------------------------------------------------------- */
 
148
/*      Load the layer list definitions.  These are fairly small.       */
 
149
/* -------------------------------------------------------------------- */
 
150
    layer_data.SetSize( 24 * layer_count );
 
151
    ReadFromFile( layer_data.buffer, 
 
152
                  512 + 28 * block_count, 
 
153
                  layer_data.buffer_size);
 
154
 
 
155
    partial_loaded = true;
 
156
 
 
157
//    FullLoad();
 
158
}
 
159
 
 
160
/************************************************************************/
 
161
/*                              FullLoad()                              */
 
162
/*                                                                      */
 
163
/*      Load the blockmap data (can be large) into blockmap_data.       */
 
164
/************************************************************************/
 
165
 
 
166
void SysBlockMap::FullLoad()
 
167
 
 
168
{
 
169
    PartialLoad();
 
170
 
 
171
    if( full_loaded )
 
172
        return;
 
173
 
 
174
//    printf( "<FullLoad>" );
 
175
//    fflush( stdout );
 
176
 
 
177
    // TODO: this should likely be protected by a mutex. 
 
178
 
 
179
/* -------------------------------------------------------------------- */
 
180
/*      Load the segment contents into a buffer.                        */
 
181
/* -------------------------------------------------------------------- */
 
182
    blockmap_data.SetSize( block_count * 28 );
 
183
    ReadFromFile( blockmap_data.buffer, 512, blockmap_data.buffer_size );
 
184
 
 
185
    full_loaded = true;
145
186
}
146
187
 
147
188
/************************************************************************/
151
192
void SysBlockMap::Synchronize()
152
193
 
153
194
{
154
 
    if( !loaded || !dirty )
 
195
    if( !full_loaded || !dirty )
155
196
        return;
156
197
 
157
 
    WriteToFile( seg_data.buffer, 0, seg_data.buffer_size );
 
198
    PCIDSKBuffer init_data(512);
 
199
 
 
200
    init_data.Put( "VERSION  1", 0, 10 );
 
201
    init_data.Put( (int) virtual_files.size(), 10, 8 );
 
202
    init_data.Put( block_count, 18, 8 );
 
203
    init_data.Put( first_free_block, 26, 8 );
 
204
    init_data.Put( "", 34, 512-34 );
 
205
 
 
206
    WriteToFile( init_data.buffer, 0, init_data.buffer_size );
 
207
 
 
208
    WriteToFile( blockmap_data.buffer, 512, blockmap_data.buffer_size );
 
209
    WriteToFile( layer_data.buffer, 512 + blockmap_data.buffer_size, 
 
210
                 layer_data.buffer_size );
158
211
 
159
212
    dirty = false;
160
213
}
168
221
void SysBlockMap::AllocateBlocks()
169
222
 
170
223
{
 
224
    FullLoad();
 
225
 
171
226
/* -------------------------------------------------------------------- */
172
227
/*      Find a segment we can extend.  We consider any SYS segments     */
173
228
/*      with a name of SysBData.                                        */
214
269
/*      Allocate another set of space.                                  */
215
270
/* -------------------------------------------------------------------- */
216
271
    uint64 new_big_blocks = 16;
217
 
    int new_bytes = new_big_blocks * SysVirtualFile::block_size;
 
272
    uint64 new_bytes = new_big_blocks * SysVirtualFile::block_size;
218
273
    seg = file->GetSegment( growing_segment );
219
 
    int block_index_in_segment = 
220
 
        seg->GetContentSize() / SysVirtualFile::block_size;
 
274
    int block_index_in_segment = (int) 
 
275
        (seg->GetContentSize() / SysVirtualFile::block_size);
221
276
 
222
277
    seg->WriteToFile( "\0", seg->GetContentSize() + new_bytes - 1, 1 );
223
278
    
224
279
/* -------------------------------------------------------------------- */
225
 
/*      Resize the SysBMDir segment data, growing the block map area.    */
 
280
/*      Resize the memory image of the blockmap.                        */
226
281
/* -------------------------------------------------------------------- */
227
 
    if( block_map_offset + 28 * (block_count + new_big_blocks) 
228
 
        + virtual_files.size() * 24 > (unsigned int) seg_data.buffer_size )
229
 
        seg_data.SetSize( 
230
 
            block_map_offset + 28 * (block_count + new_big_blocks) 
231
 
            + virtual_files.size() * 24 );
232
 
 
233
 
    // push the layer list on.
234
 
    memmove( seg_data.buffer + layer_list_offset + new_big_blocks*28, 
235
 
             seg_data.buffer + layer_list_offset, 
236
 
             virtual_files.size() * 24 );
 
282
    if( 28 * (block_count + new_big_blocks) 
 
283
        > (unsigned int) blockmap_data.buffer_size )
 
284
        blockmap_data.SetSize( (int) (28 * (block_count + new_big_blocks)) );
237
285
 
238
286
/* -------------------------------------------------------------------- */
239
287
/*      Fill in info on the new blocks.                                 */
244
292
         block_index < block_count + new_big_blocks;
245
293
         block_index++ )
246
294
    {
247
 
        uint64 bi_offset = block_map_offset + block_index * 28;
 
295
        int bi_offset = (int) (block_index * 28);
248
296
 
249
 
        seg_data.Put( growing_segment, bi_offset, 4 );
250
 
        seg_data.Put( block_index_in_segment++, bi_offset+4, 8 );
251
 
        seg_data.Put( -1, bi_offset+12, 8 );
 
297
        blockmap_data.Put( growing_segment, bi_offset, 4 );
 
298
        blockmap_data.Put( block_index_in_segment++, bi_offset+4, 8 );
 
299
        blockmap_data.Put( -1, bi_offset+12, 8 );
252
300
 
253
301
        if( block_index == block_count + new_big_blocks - 1 )
254
 
            seg_data.Put( -1, bi_offset+20, 8 );
 
302
            blockmap_data.Put( -1, bi_offset+20, 8 );
255
303
        else
256
 
            seg_data.Put( block_index+1, bi_offset+20, 8 );
 
304
            blockmap_data.Put( block_index+1, bi_offset+20, 8 );
257
305
    }
258
306
 
259
307
    first_free_block = block_count;
260
 
    seg_data.Put( first_free_block, 26, 8 );
261
 
 
262
 
    block_count += new_big_blocks;
263
 
    seg_data.Put( block_count, 18, 8 );
264
 
 
265
 
    layer_list_offset = block_map_offset + 28 * block_count;
 
308
 
 
309
    block_count += (int) new_big_blocks;
266
310
 
267
311
    dirty = true;
268
312
}
277
321
                                  int &block_segment_ret )
278
322
 
279
323
{
280
 
    Load();
 
324
    FullLoad();
281
325
 
282
326
/* -------------------------------------------------------------------- */
283
327
/*      Do we need to create new free blocks?                           */
292
336
    int alloc_block = first_free_block;
293
337
 
294
338
    // update first free block to point to the next free block.
295
 
    first_free_block = seg_data.GetInt( block_map_offset+alloc_block*28+20, 8);
296
 
    seg_data.Put( first_free_block, 26, 8 );
 
339
    first_free_block = blockmap_data.GetInt( alloc_block*28+20, 8);
297
340
 
298
341
    // mark block as owned by this layer/image. 
299
 
    seg_data.Put( image, block_map_offset + alloc_block*28 + 12, 8 );
 
342
    blockmap_data.Put( image, alloc_block*28 + 12, 8 );
300
343
 
301
344
    // clear next free block on allocated block - it is the last in the chain
302
 
    seg_data.Put( -1, block_map_offset + alloc_block*28 + 20, 8 );
 
345
    blockmap_data.Put( -1, alloc_block*28 + 20, 8 );
303
346
 
304
347
    // point the previous "last block" for this virtual file to this new block
305
348
    if( last_block != -1 )
306
 
        seg_data.Put( alloc_block, block_map_offset + last_block*28 + 20, 8 );
 
349
        blockmap_data.Put( alloc_block, last_block*28 + 20, 8 );
307
350
    else
308
 
        seg_data.Put( alloc_block, layer_list_offset + image*24 + 4, 8 );
 
351
        layer_data.Put( alloc_block, image*24 + 4, 8 );
309
352
 
310
353
    dirty = true;
311
354
 
312
 
    block_segment_ret = seg_data.GetInt( block_map_offset+alloc_block*28, 4 );
 
355
    block_segment_ret = blockmap_data.GetInt( alloc_block*28, 4 );
313
356
    last_block = alloc_block;
314
357
 
315
 
    return seg_data.GetInt( block_map_offset+alloc_block*28+4, 8 );
 
358
    return blockmap_data.GetInt( alloc_block*28+4, 8 );
316
359
}
317
360
 
318
361
/************************************************************************/
322
365
void SysBlockMap::SetVirtualFileSize( int image_index, uint64 file_length )
323
366
 
324
367
{
325
 
    seg_data.Put( file_length, layer_list_offset + 24*image_index + 12, 12 );
 
368
    FullLoad();
 
369
 
 
370
    layer_data.Put( file_length, 24*image_index + 12, 12 );
326
371
    dirty = true;
327
372
}
328
373
 
333
378
SysVirtualFile *SysBlockMap::GetVirtualFile( int image )
334
379
 
335
380
{
336
 
    Load();
 
381
    PartialLoad();
337
382
 
338
383
    if( image < 0 || image >= (int) virtual_files.size() )
339
384
        ThrowPCIDSKException( "GetImageSysFile(%d): invalid image index",
340
 
                                   image );
 
385
                              image );
341
386
 
342
387
    if( virtual_files[image] != NULL )
343
388
        return virtual_files[image];
344
389
 
345
 
    uint64  vfile_length = 
346
 
        seg_data.GetUInt64( layer_list_offset + 24*image + 12, 12 );
347
 
    int  start_block = 
348
 
        seg_data.GetInt( layer_list_offset + 24*image + 4, 8 );
 
390
    uint64  vfile_length = layer_data.GetUInt64( 24*image + 12, 12 );
 
391
    int  start_block = layer_data.GetInt( 24*image + 4, 8 );
349
392
 
350
393
    virtual_files[image] = 
351
 
        new SysVirtualFile( dynamic_cast<CPCIDSKFile *>(file), start_block, vfile_length, seg_data,
 
394
        new SysVirtualFile( dynamic_cast<CPCIDSKFile *>(file), 
 
395
                            start_block, vfile_length,
352
396
                            this, image );
353
397
 
354
398
    return virtual_files[image];
361
405
int SysBlockMap::CreateVirtualFile()
362
406
 
363
407
{
364
 
    Load();
 
408
    FullLoad();
365
409
 
366
410
/* -------------------------------------------------------------------- */
367
411
/*      Is there an existing dead layer we can reuse?                   */
370
414
 
371
415
    for( layer_index = 0; layer_index < virtual_files.size(); layer_index++ )
372
416
    {
373
 
        if( seg_data.GetInt( layer_list_offset + 24*layer_index + 0, 4 )
374
 
            == 1 /* dead */ )
 
417
        if( layer_data.GetInt( 24*layer_index + 0, 4 ) == 1 /* dead */ )
375
418
        {
376
419
            break;
377
420
        }
382
425
/* -------------------------------------------------------------------- */
383
426
    if( layer_index == virtual_files.size() )
384
427
    {
385
 
        seg_data.Put( (int) layer_index+1, 10, 8 );
386
 
        
387
 
        if( layer_list_offset + (virtual_files.size()+1) * 24 
388
 
            > (unsigned int) seg_data.buffer_size )
389
 
            seg_data.SetSize( layer_list_offset + (virtual_files.size()+1) * 24  );
390
 
 
391
 
        virtual_files.resize(layer_index+1);
392
 
        virtual_files[layer_index] = NULL;
 
428
        layer_index = virtual_files.size();
 
429
        layer_data.SetSize( (layer_index+1) * 24 );
 
430
        virtual_files.push_back( NULL );
393
431
    }
394
432
 
395
433
/* -------------------------------------------------------------------- */
397
435
/* -------------------------------------------------------------------- */
398
436
    dirty = true;
399
437
 
400
 
    seg_data.Put( 2, layer_list_offset + 24*layer_index + 0, 4 );
401
 
    seg_data.Put( -1, layer_list_offset + 24*layer_index + 4, 8 );
402
 
    seg_data.Put( 0, layer_list_offset + 24*layer_index + 12, 12 );
 
438
    layer_data.Put( 2, 24*layer_index + 0, 4 );
 
439
    layer_data.Put( -1, 24*layer_index + 4, 8 );
 
440
    layer_data.Put( 0, 24*layer_index + 12, 12 );
403
441
 
404
442
    return layer_index;
405
443
}
459
497
 
460
498
    return img_index;
461
499
}
 
500
 
 
501
/************************************************************************/
 
502
/*                        GetNextBlockMapEntry()                        */
 
503
/*                                                                      */
 
504
/*      SysVirtualFile's call this method to find the next block in     */
 
505
/*      the blockmap which belongs to them.  This allows them to        */
 
506
/*      fill their blockmap "as needed" without necessarily forcing     */
 
507
/*      a full load of the blockmap.                                    */
 
508
/************************************************************************/
 
509
 
 
510
int SysBlockMap::GetNextBlockMapEntry( int bm_index,
 
511
                                       uint16 &segment,
 
512
                                       int &block_in_segment )
 
513
 
 
514
{
 
515
    if( !partial_loaded )
 
516
        PartialLoad();
 
517
 
 
518
/* -------------------------------------------------------------------- */
 
519
/*      If the full blockmap is already loaded, just fetch it from      */
 
520
/*      there to avoid extra IO or confusion between what is disk       */
 
521
/*      and what is in memory.                                          */
 
522
/*                                                                      */
 
523
/*      Otherwise we read from disk and hope the io level buffering     */
 
524
/*      is pretty good.                                                 */
 
525
/* -------------------------------------------------------------------- */
 
526
    char bm_entry[29];
 
527
 
 
528
    if( full_loaded )
 
529
    {
 
530
        memcpy( bm_entry, blockmap_data.buffer + bm_index * 28, 28 );
 
531
    }
 
532
    else
 
533
    {
 
534
        ReadFromFile( bm_entry, bm_index * 28 + 512, 28 );
 
535
    }
 
536
    
 
537
/* -------------------------------------------------------------------- */
 
538
/*      Parse the values as efficiently as we can.                      */
 
539
/* -------------------------------------------------------------------- */
 
540
    bm_entry[28] = '\0';
 
541
 
 
542
    int next_block = atoi( bm_entry+20 );
 
543
 
 
544
    bm_entry[12] = '\0';
 
545
    block_in_segment = atoi(bm_entry+4);
 
546
 
 
547
    bm_entry[4] = '\0';
 
548
    segment = atoi(bm_entry);
 
549
    
 
550
    return next_block;
 
551
}