1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the CPCIDSKFile class.
4 : *
5 : ******************************************************************************
6 : * Copyright (c) 2009
7 : * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
8 : *
9 : * Permission is hereby granted, free of charge, to any person obtaining a
10 : * copy of this software and associated documentation files (the "Software"),
11 : * to deal in the Software without restriction, including without limitation
12 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 : * and/or sell copies of the Software, and to permit persons to whom the
14 : * Software is furnished to do so, subject to the following conditions:
15 : *
16 : * The above copyright notice and this permission notice shall be included
17 : * in all copies or substantial portions of the Software.
18 : *
19 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 : * DEALINGS IN THE SOFTWARE.
26 : ****************************************************************************/
27 : #include "pcidsk_file.h"
28 : #include "pcidsk_exception.h"
29 : #include "pcidsk_channel.h"
30 : #include "pcidsk_segment.h"
31 : #include "core/mutexholder.h"
32 : #include "core/pcidsk_utils.h"
33 : #include "core/cpcidskfile.h"
34 :
35 : // Channel types
36 : #include "channel/cbandinterleavedchannel.h"
37 : #include "channel/cpixelinterleavedchannel.h"
38 : #include "channel/ctiledchannel.h"
39 : #include "channel/cexternalchannel.h"
40 :
41 : // Segment types
42 : #include "segment/cpcidskgeoref.h"
43 : #include "segment/cpcidskpct.h"
44 : #include "segment/cpcidskvectorsegment.h"
45 : #include "segment/metadatasegment.h"
46 : #include "segment/sysblockmap.h"
47 : #include "segment/cpcidskrpcmodel.h"
48 : #include "segment/cpcidskgcp2segment.h"
49 : #include "segment/cpcidskbitmap.h"
50 : #include "segment/cpcidsk_tex.h"
51 : #include "segment/cpcidsk_array.h"
52 : #include "segment/cpcidskapmodel.h"
53 : #include "segment/cpcidskads40model.h"
54 : #include "segment/cpcidsktoutinmodel.h"
55 : #include "segment/cpcidskpolymodel.h"
56 : #include "segment/cpcidskbinarysegment.h"
57 : #include "core/clinksegment.h"
58 :
59 : #include <cassert>
60 : #include <cstdlib>
61 : #include <cstring>
62 : #include <cstdio>
63 : #include <string>
64 :
65 : #include <iostream>
66 :
67 : using namespace PCIDSK;
68 :
69 : /************************************************************************/
70 : /* CPCIDSKFile() */
71 : /************************************************************************/
72 :
73 110 : CPCIDSKFile::CPCIDSKFile( std::string filename )
74 :
75 : {
76 110 : io_handle = NULL;
77 110 : io_mutex = NULL;
78 110 : updatable = false;
79 110 : base_filename = filename;
80 :
81 : /* -------------------------------------------------------------------- */
82 : /* Initialize the metadata object, but do not try to load till */
83 : /* needed. */
84 : /* -------------------------------------------------------------------- */
85 110 : metadata.Initialize( this, "FIL", 0 );
86 110 : }
87 :
88 : /************************************************************************/
89 : /* ~CPCIDSKFile() */
90 : /************************************************************************/
91 :
92 110 : CPCIDSKFile::~CPCIDSKFile()
93 :
94 : {
95 110 : Synchronize();
96 :
97 : /* -------------------------------------------------------------------- */
98 : /* Cleanup last block buffer. */
99 : /* -------------------------------------------------------------------- */
100 110 : if( last_block_data != NULL )
101 : {
102 0 : last_block_index = -1;
103 0 : free( last_block_data );
104 0 : last_block_data = NULL;
105 0 : delete last_block_mutex;
106 : }
107 :
108 : /* -------------------------------------------------------------------- */
109 : /* Cleanup channels and segments. */
110 : /* -------------------------------------------------------------------- */
111 : size_t i;
112 291 : for( i = 0; i < channels.size(); i++ )
113 : {
114 181 : delete channels[i];
115 181 : channels[i] = NULL;
116 : }
117 :
118 112860 : for( i = 0; i < segments.size(); i++ )
119 : {
120 112750 : delete segments[i];
121 112750 : segments[i] = NULL;
122 : }
123 :
124 : /* -------------------------------------------------------------------- */
125 : /* Close and cleanup IO stuff. */
126 : /* -------------------------------------------------------------------- */
127 : {
128 110 : MutexHolder oHolder( io_mutex );
129 :
130 110 : if( io_handle )
131 : {
132 110 : interfaces.io->Close( io_handle );
133 110 : io_handle = NULL;
134 110 : }
135 : }
136 :
137 : size_t i_file;
138 :
139 112 : for( i_file=0; i_file < file_list.size(); i_file++ )
140 : {
141 2 : delete file_list[i_file].io_mutex;
142 2 : file_list[i_file].io_mutex = NULL;
143 :
144 2 : interfaces.io->Close( file_list[i_file].io_handle );
145 2 : file_list[i_file].io_handle = NULL;
146 : }
147 :
148 110 : for( i_file=0; i_file < edb_file_list.size(); i_file++ )
149 : {
150 0 : delete edb_file_list[i_file].io_mutex;
151 0 : edb_file_list[i_file].io_mutex = NULL;
152 :
153 0 : delete edb_file_list[i_file].file;
154 0 : edb_file_list[i_file].file = NULL;
155 : }
156 :
157 110 : delete io_mutex;
158 110 : }
159 :
160 : /************************************************************************/
161 : /* Synchronize() */
162 : /************************************************************************/
163 :
164 208 : void CPCIDSKFile::Synchronize()
165 :
166 : {
167 208 : if( !GetUpdatable() )
168 96 : return;
169 :
170 : /* -------------------------------------------------------------------- */
171 : /* Flush out last line caching stuff for pixel interleaved data. */
172 : /* -------------------------------------------------------------------- */
173 112 : FlushBlock();
174 :
175 : /* -------------------------------------------------------------------- */
176 : /* Synchronize all channels. */
177 : /* -------------------------------------------------------------------- */
178 : size_t i;
179 297 : for( i = 0; i < channels.size(); i++ )
180 185 : channels[i]->Synchronize();
181 :
182 : /* -------------------------------------------------------------------- */
183 : /* Synchronize all segments we have instantiated. */
184 : /* -------------------------------------------------------------------- */
185 114912 : for( i = 0; i < segments.size(); i++ )
186 : {
187 114800 : if( segments[i] != NULL )
188 183 : segments[i]->Synchronize();
189 : }
190 :
191 : /* -------------------------------------------------------------------- */
192 : /* Ensure the file is synhronized to disk. */
193 : /* -------------------------------------------------------------------- */
194 112 : MutexHolder oHolder( io_mutex );
195 :
196 112 : interfaces.io->Flush( io_handle );
197 : }
198 :
199 : /************************************************************************/
200 : /* GetChannel() */
201 : /************************************************************************/
202 :
203 368 : PCIDSKChannel *CPCIDSKFile::GetChannel( int band )
204 :
205 : {
206 368 : if( band < 1 || band > channel_count )
207 : ThrowPCIDSKException( "Out of range band (%d) requested.",
208 0 : band );
209 :
210 368 : return channels[band-1];
211 : }
212 :
213 : /************************************************************************/
214 : /* GetSegment() */
215 : /************************************************************************/
216 :
217 392 : PCIDSK::PCIDSKSegment *CPCIDSKFile::GetSegment( int segment )
218 :
219 : {
220 : /* -------------------------------------------------------------------- */
221 : /* Is this a valid segment? */
222 : /* -------------------------------------------------------------------- */
223 392 : if( segment < 1 || segment > segment_count )
224 0 : return NULL;
225 :
226 392 : const char *segment_pointer = segment_pointers.buffer + (segment-1) * 32;
227 392 : if( segment_pointer[0] != 'A' && segment_pointer[0] != 'L' )
228 0 : return NULL;
229 :
230 : /* -------------------------------------------------------------------- */
231 : /* Do we already have a corresponding object? */
232 : /* -------------------------------------------------------------------- */
233 392 : if( segments[segment] != NULL )
234 229 : return segments[segment];
235 :
236 : /* -------------------------------------------------------------------- */
237 : /* Instantiate per the type. */
238 : /* -------------------------------------------------------------------- */
239 163 : int segment_type = segment_pointers.GetInt((segment-1)*32+1,3);
240 163 : PCIDSKSegment *segobj = NULL;
241 :
242 163 : switch( segment_type )
243 : {
244 : case SEG_GEO:
245 54 : segobj = new CPCIDSKGeoref( this, segment, segment_pointer );
246 54 : break;
247 :
248 : case SEG_PCT:
249 2 : segobj = new CPCIDSK_PCT( this, segment, segment_pointer );
250 2 : break;
251 :
252 : case SEG_VEC:
253 28 : segobj = new CPCIDSKVectorSegment( this, segment, segment_pointer );
254 28 : break;
255 :
256 : case SEG_BIT:
257 8 : segobj = new CPCIDSKBitmap( this, segment, segment_pointer );
258 8 : break;
259 :
260 : case SEG_TEX:
261 0 : segobj = new CPCIDSK_TEX( this, segment, segment_pointer );
262 0 : break;
263 :
264 : case SEG_SYS:
265 71 : if( strncmp(segment_pointer + 4, "SysBMDir",8) == 0 )
266 14 : segobj = new SysBlockMap( this, segment, segment_pointer );
267 57 : else if( strncmp(segment_pointer + 4, "METADATA",8) == 0 )
268 43 : segobj = new MetadataSegment( this, segment, segment_pointer );
269 14 : else if (strncmp(segment_pointer + 4, "Link ", 8) == 0)
270 0 : segobj = new CLinkSegment(this, segment, segment_pointer);
271 : else
272 14 : segobj = new CPCIDSKSegment( this, segment, segment_pointer );
273 :
274 71 : break;
275 :
276 : case SEG_GCP2:
277 0 : segobj = new CPCIDSKGCP2Segment(this, segment, segment_pointer);
278 0 : break;
279 :
280 : case SEG_ORB:
281 0 : segobj = new CPCIDSKEphemerisSegment(this, segment, segment_pointer);
282 0 : break;
283 :
284 : case SEG_ARR:
285 0 : segobj = new CPCIDSK_ARRAY(this, segment, segment_pointer);
286 0 : break;
287 :
288 : case SEG_BIN:
289 0 : if (!strncmp(segment_pointer + 4, "RFMODEL ", 8))
290 : {
291 0 : segobj = new CPCIDSKRPCModelSegment( this, segment, segment_pointer );
292 : }
293 0 : else if (!strncmp(segment_pointer + 4, "APMODEL ", 8))
294 : {
295 0 : segobj = new CPCIDSKAPModelSegment(this, segment, segment_pointer);
296 : }
297 0 : else if (!strncmp(segment_pointer + 4, "ADSMODEL", 8))
298 : {
299 0 : segobj = new CPCIDSKADS40ModelSegment(this, segment, segment_pointer);
300 : }
301 0 : else if (!strncmp(segment_pointer + 4, "POLYMDL ", 8))
302 : {
303 0 : segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
304 : }
305 0 : else if (!strncmp(segment_pointer + 4, "TPSMODEL", 8))
306 : {
307 0 : segobj = new CPCIDSKGCP2Segment(this, segment, segment_pointer);
308 : }
309 0 : else if (!strncmp(segment_pointer + 4, "MODEL ", 8))
310 : {
311 0 : segobj = new CPCIDSKToutinModelSegment(this, segment, segment_pointer);
312 : }
313 0 : else if (!strncmp(segment_pointer + 4, "MMSPB ", 8))
314 : {
315 0 : segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
316 : }
317 0 : else if (!strncmp(segment_pointer + 4, "MMADS ", 8))
318 : {
319 0 : segobj = new CPCIDSKBinarySegment(this, segment, segment_pointer);
320 : }
321 : break;
322 : }
323 :
324 163 : if (segobj == NULL)
325 0 : segobj = new CPCIDSKSegment( this, segment, segment_pointer );
326 :
327 163 : segments[segment] = segobj;
328 :
329 163 : return segobj;
330 : }
331 :
332 : /************************************************************************/
333 : /* GetSegment() */
334 : /* */
335 : /* Find segment by type/name. */
336 : /************************************************************************/
337 :
338 560 : PCIDSK::PCIDSKSegment *CPCIDSKFile::GetSegment( int type, std::string name,
339 : int previous )
340 :
341 : {
342 : int i;
343 : char type_str[4];
344 :
345 560 : name += " "; // white space pad name.
346 :
347 : //we want the 3 less significant digit only in case type is too big
348 : // Note : that happen with SEG_VEC_TABLE that is equal to 65652 in GDB.
349 : //see function BuildChildrenLayer in jtfile.cpp, the call on GDBSegNext
350 : //in the loop on gasTypeTable can create issue in PCIDSKSegNext
351 : //(in pcic/gdbfrtms/pcidskopen.cpp)
352 560 : sprintf( type_str, "%03d", (type % 1000) );
353 :
354 544146 : for( i = previous; i < segment_count; i++ )
355 : {
356 543728 : if( type != SEG_UNKNOWN
357 : && strncmp(segment_pointers.buffer+i*32+1,type_str,3) != 0 )
358 543530 : continue;
359 :
360 198 : if( name != " "
361 : && strncmp(segment_pointers.buffer+i*32+4,name.c_str(),8) != 0 )
362 56 : continue;
363 :
364 : // Ignore deleted segments.
365 142 : if (*(segment_pointers.buffer + i * 32 + 0) == 'D') continue;
366 :
367 142 : return GetSegment(i+1);
368 : }
369 :
370 418 : return NULL;
371 : }
372 :
373 :
374 : /************************************************************************/
375 : /* GetSegments() */
376 : /************************************************************************/
377 :
378 0 : std::vector<PCIDSK::PCIDSKSegment *> CPCIDSKFile::GetSegments()
379 :
380 : {
381 0 : PCIDSK::ThrowPCIDSKException( "Objects list access not implemented yet." );
382 :
383 0 : std::vector<PCIDSK::PCIDSKSegment *> list;
384 : return list;
385 : }
386 :
387 : /************************************************************************/
388 : /* InitializeFromHeader() */
389 : /************************************************************************/
390 :
391 110 : void CPCIDSKFile::InitializeFromHeader()
392 :
393 : {
394 : /* -------------------------------------------------------------------- */
395 : /* Process the file header. */
396 : /* -------------------------------------------------------------------- */
397 110 : PCIDSKBuffer fh(512);
398 :
399 110 : ReadFromFile( fh.buffer, 0, 512 );
400 :
401 110 : width = atoi(fh.Get(384,8));
402 110 : height = atoi(fh.Get(392,8));
403 110 : channel_count = atoi(fh.Get(376,8));
404 110 : file_size = fh.GetUInt64(16,16);
405 :
406 110 : uint64 ih_start_block = atouint64(fh.Get(336,16));
407 110 : uint64 image_start_block = atouint64(fh.Get(304,16));
408 110 : fh.Get(360,8,interleaving);
409 :
410 110 : uint64 image_offset = (image_start_block-1) * 512;
411 :
412 110 : block_size = 0;
413 110 : last_block_index = -1;
414 110 : last_block_dirty = 0;
415 110 : last_block_data = NULL;
416 110 : last_block_mutex = NULL;
417 :
418 : /* -------------------------------------------------------------------- */
419 : /* Load the segment pointers into a PCIDSKBuffer. For now we */
420 : /* try to avoid doing too much other processing on them. */
421 : /* -------------------------------------------------------------------- */
422 110 : int segment_block_count = atoi(fh.Get(456,8));
423 :
424 110 : segment_count = (segment_block_count * 512) / 32;
425 110 : segment_pointers.SetSize( segment_block_count * 512 );
426 110 : segment_pointers_offset = atouint64(fh.Get(440,16)) * 512 - 512;
427 : ReadFromFile( segment_pointers.buffer, segment_pointers_offset,
428 110 : segment_block_count * 512 );
429 :
430 110 : segments.resize( segment_count + 1 );
431 :
432 : /* -------------------------------------------------------------------- */
433 : /* Get the number of each channel type - only used for some */
434 : /* interleaving cases. */
435 : /* -------------------------------------------------------------------- */
436 110 : int count_8u = 0, count_16s = 0, count_16u = 0, count_32r = 0;
437 110 : int count_c16u = 0, count_c16s = 0, count_c32r = 0;
438 :
439 110 : if (strcmp(fh.Get(464,4), " ") == 0)
440 : {
441 0 : count_8u = channel_count;
442 : }
443 : else
444 : {
445 110 : count_8u = atoi(fh.Get(464,4));
446 110 : count_16s = atoi(fh.Get(468,4));
447 110 : count_16u = atoi(fh.Get(472,4));
448 110 : count_32r = atoi(fh.Get(476,4));
449 110 : count_c16u = atoi(fh.Get(480,4));
450 110 : count_c16s = atoi(fh.Get(484,4));
451 110 : count_c32r = atoi(fh.Get(488,4));
452 : }
453 : /* -------------------------------------------------------------------- */
454 : /* for pixel interleaved files we need to compute the length of */
455 : /* a scanline padded out to a 512 byte boundary. */
456 : /* -------------------------------------------------------------------- */
457 110 : if( interleaving == "PIXEL" )
458 : {
459 0 : first_line_offset = image_offset;
460 0 : pixel_group_size = count_8u + count_16s*2 + count_16u*2 + count_32r*4;
461 :
462 0 : block_size = pixel_group_size * width;
463 0 : if( block_size % 512 != 0 )
464 0 : block_size += 512 - (block_size % 512);
465 :
466 0 : last_block_data = malloc((size_t) block_size);
467 0 : if( last_block_data == NULL )
468 : ThrowPCIDSKException( "Allocating %d bytes for scanline buffer failed.",
469 0 : (int) block_size );
470 :
471 0 : last_block_mutex = interfaces.CreateMutex();
472 0 : image_offset = 0;
473 : }
474 :
475 : /* -------------------------------------------------------------------- */
476 : /* Initialize the list of channels. */
477 : /* -------------------------------------------------------------------- */
478 : int channelnum;
479 :
480 291 : for( channelnum = 1; channelnum <= channel_count; channelnum++ )
481 : {
482 181 : PCIDSKBuffer ih(1024);
483 181 : PCIDSKChannel *channel = NULL;
484 181 : uint64 ih_offset = (ih_start_block-1)*512 + (channelnum-1)*1024;
485 :
486 181 : ReadFromFile( ih.buffer, ih_offset, 1024 );
487 :
488 : // fetch the filename, if there is one.
489 181 : std::string filename;
490 181 : ih.Get(64,64,filename);
491 :
492 : // adjust it relative to the path of the pcidsk file.
493 : filename = MergeRelativePath( interfaces.io,
494 181 : base_filename, filename );
495 :
496 : // work out channel type from header
497 : eChanType pixel_type;
498 181 : const char *pixel_type_string = ih.Get( 160, 8 );
499 :
500 181 : pixel_type = GetDataTypeFromName(pixel_type_string);
501 :
502 : // if we didn't get channel type in header, work out from counts (old).
503 : // Check this only if we don't have complex channels:
504 :
505 181 : if (strncmp(pixel_type_string," ",8) == 0 )
506 : {
507 0 : assert( count_c32r == 0 && count_c16u == 0 && count_c16s == 0 );
508 0 : if( channelnum <= count_8u )
509 0 : pixel_type = CHN_8U;
510 0 : else if( channelnum <= count_8u + count_16s )
511 0 : pixel_type = CHN_16S;
512 0 : else if( channelnum <= count_8u + count_16s + count_16u )
513 0 : pixel_type = CHN_16U;
514 : else
515 0 : pixel_type = CHN_32R;
516 : }
517 :
518 181 : if( interleaving == "BAND" )
519 : {
520 : channel = new CBandInterleavedChannel( ih, ih_offset, fh,
521 : channelnum, this,
522 169 : image_offset, pixel_type );
523 :
524 :
525 169 : image_offset += (int64)DataTypeSize(channel->GetType())
526 507 : * (int64)width * (int64)height;
527 : }
528 :
529 12 : else if( interleaving == "PIXEL" )
530 : {
531 : channel = new CPixelInterleavedChannel( ih, ih_offset, fh,
532 : channelnum, this,
533 : (int) image_offset,
534 0 : pixel_type );
535 0 : image_offset += DataTypeSize(pixel_type);
536 : }
537 :
538 12 : else if( interleaving == "FILE"
539 : && strncmp(filename.c_str(),"/SIS=",5) == 0 )
540 : {
541 : channel = new CTiledChannel( ih, ih_offset, fh,
542 9 : channelnum, this, pixel_type );
543 : }
544 :
545 3 : else if( interleaving == "FILE"
546 : && filename != ""
547 : && strncmp(((const char*)ih.buffer)+250, " ", 8 ) != 0 )
548 : {
549 : channel = new CExternalChannel( ih, ih_offset, fh, filename,
550 0 : channelnum, this, pixel_type );
551 : }
552 :
553 3 : else if( interleaving == "FILE" )
554 : {
555 : channel = new CBandInterleavedChannel( ih, ih_offset, fh,
556 : channelnum, this,
557 3 : 0, pixel_type );
558 : }
559 :
560 : else
561 : ThrowPCIDSKException( "Unsupported interleaving:%s",
562 0 : interleaving.c_str() );
563 :
564 181 : channels.push_back( channel );
565 110 : }
566 110 : }
567 :
568 : /************************************************************************/
569 : /* ReadFromFile() */
570 : /************************************************************************/
571 :
572 2182 : void CPCIDSKFile::ReadFromFile( void *buffer, uint64 offset, uint64 size )
573 :
574 : {
575 2182 : MutexHolder oHolder( io_mutex );
576 :
577 2182 : interfaces.io->Seek( io_handle, offset, SEEK_SET );
578 2182 : if( interfaces.io->Read( buffer, 1, size, io_handle ) != size )
579 : ThrowPCIDSKException( "PCIDSKFile:Failed to read %d bytes at %d.",
580 0 : (int) size, (int) offset );
581 2182 : }
582 :
583 : /************************************************************************/
584 : /* WriteToFile() */
585 : /************************************************************************/
586 :
587 880 : void CPCIDSKFile::WriteToFile( const void *buffer, uint64 offset, uint64 size )
588 :
589 : {
590 880 : if( !GetUpdatable() )
591 0 : throw PCIDSKException( "File not open for update in WriteToFile()" );
592 :
593 880 : MutexHolder oHolder( io_mutex );
594 :
595 880 : interfaces.io->Seek( io_handle, offset, SEEK_SET );
596 880 : if( interfaces.io->Write( buffer, 1, size, io_handle ) != size )
597 : ThrowPCIDSKException( "PCIDSKFile:Failed to write %d bytes at %d.",
598 0 : (int) size, (int) offset );
599 880 : }
600 :
601 : /************************************************************************/
602 : /* ReadAndLockBlock() */
603 : /************************************************************************/
604 :
605 0 : void *CPCIDSKFile::ReadAndLockBlock( int block_index,
606 : int win_xoff, int win_xsize )
607 :
608 : {
609 0 : if( last_block_data == NULL )
610 0 : ThrowPCIDSKException( "ReadAndLockBlock() called on a file that is not pixel interleaved." );
611 :
612 : /* -------------------------------------------------------------------- */
613 : /* Default, and validate windowing. */
614 : /* -------------------------------------------------------------------- */
615 0 : if( win_xoff == -1 && win_xsize == -1 )
616 : {
617 0 : win_xoff = 0;
618 0 : win_xsize = GetWidth();
619 : }
620 :
621 0 : if( win_xoff < 0 || win_xoff+win_xsize > GetWidth() )
622 : {
623 : ThrowPCIDSKException( "CPCIDSKFile::ReadAndLockBlock(): Illegal window - xoff=%d, xsize=%d",
624 0 : win_xoff, win_xsize );
625 : }
626 :
627 0 : if( block_index == last_block_index
628 : && win_xoff == last_block_xoff
629 : && win_xsize == last_block_xsize )
630 : {
631 0 : last_block_mutex->Acquire();
632 0 : return last_block_data;
633 : }
634 :
635 : /* -------------------------------------------------------------------- */
636 : /* Flush any dirty writable data. */
637 : /* -------------------------------------------------------------------- */
638 0 : FlushBlock();
639 :
640 : /* -------------------------------------------------------------------- */
641 : /* Read the requested window. */
642 : /* -------------------------------------------------------------------- */
643 0 : last_block_mutex->Acquire();
644 :
645 : ReadFromFile( last_block_data,
646 : first_line_offset + block_index*block_size
647 : + win_xoff * pixel_group_size,
648 0 : pixel_group_size * win_xsize );
649 0 : last_block_index = block_index;
650 0 : last_block_xoff = win_xoff;
651 0 : last_block_xsize = win_xsize;
652 :
653 0 : return last_block_data;
654 : }
655 :
656 : /************************************************************************/
657 : /* UnlockBlock() */
658 : /************************************************************************/
659 :
660 0 : void CPCIDSKFile::UnlockBlock( bool mark_dirty )
661 :
662 : {
663 0 : if( last_block_mutex == NULL )
664 0 : return;
665 :
666 0 : last_block_dirty |= mark_dirty;
667 0 : last_block_mutex->Release();
668 : }
669 :
670 : /************************************************************************/
671 : /* WriteBlock() */
672 : /************************************************************************/
673 :
674 0 : void CPCIDSKFile::WriteBlock( int block_index, void *buffer )
675 :
676 : {
677 0 : if( !GetUpdatable() )
678 0 : throw PCIDSKException( "File not open for update in WriteBlock()" );
679 :
680 0 : if( last_block_data == NULL )
681 0 : ThrowPCIDSKException( "WriteBlock() called on a file that is not pixel interleaved." );
682 :
683 : WriteToFile( buffer,
684 : first_line_offset + block_index*block_size,
685 0 : block_size );
686 0 : }
687 :
688 : /************************************************************************/
689 : /* FlushBlock() */
690 : /************************************************************************/
691 :
692 112 : void CPCIDSKFile::FlushBlock()
693 :
694 : {
695 112 : if( last_block_dirty )
696 : {
697 0 : last_block_mutex->Acquire();
698 0 : if( last_block_dirty ) // is it still dirty?
699 : {
700 0 : WriteBlock( last_block_index, last_block_data );
701 0 : last_block_dirty = 0;
702 : }
703 0 : last_block_mutex->Release();
704 : }
705 112 : }
706 :
707 : /************************************************************************/
708 : /* GetEDBFileDetails() */
709 : /************************************************************************/
710 :
711 0 : bool CPCIDSKFile::GetEDBFileDetails( EDBFile** file_p,
712 : Mutex **io_mutex_p,
713 : std::string filename )
714 :
715 : {
716 0 : *file_p = NULL;
717 0 : *io_mutex_p = NULL;
718 :
719 : /* -------------------------------------------------------------------- */
720 : /* Does the file exist already in our file list? */
721 : /* -------------------------------------------------------------------- */
722 : unsigned int i;
723 :
724 0 : for( i = 0; i < edb_file_list.size(); i++ )
725 : {
726 0 : if( edb_file_list[i].filename == filename )
727 : {
728 0 : *file_p = edb_file_list[i].file;
729 0 : *io_mutex_p = edb_file_list[i].io_mutex;
730 0 : return edb_file_list[i].writable;
731 : }
732 : }
733 :
734 : /* -------------------------------------------------------------------- */
735 : /* If not, we need to try and open the file. Eventually we */
736 : /* will need better rules about read or update access. */
737 : /* -------------------------------------------------------------------- */
738 0 : ProtectedEDBFile new_file;
739 :
740 0 : new_file.file = NULL;
741 0 : new_file.writable = false;
742 :
743 0 : if( GetUpdatable() )
744 : {
745 : try {
746 0 : new_file.file = interfaces.OpenEDB( filename, "r+" );
747 0 : new_file.writable = true;
748 : }
749 0 : catch( PCIDSK::PCIDSKException ex ) {}
750 0 : catch( std::exception ex ) {}
751 : }
752 :
753 0 : if( new_file.file == NULL )
754 0 : new_file.file = interfaces.OpenEDB( filename, "r" );
755 :
756 0 : if( new_file.file == NULL )
757 : ThrowPCIDSKException( "Unable to open file '%s'.",
758 0 : filename.c_str() );
759 :
760 : /* -------------------------------------------------------------------- */
761 : /* Push the new file into the list of files managed for this */
762 : /* PCIDSK file. */
763 : /* -------------------------------------------------------------------- */
764 0 : new_file.io_mutex = interfaces.CreateMutex();
765 0 : new_file.filename = filename;
766 :
767 0 : edb_file_list.push_back( new_file );
768 :
769 0 : *file_p = edb_file_list[edb_file_list.size()-1].file;
770 0 : *io_mutex_p = edb_file_list[edb_file_list.size()-1].io_mutex;
771 :
772 0 : return new_file.writable;
773 : }
774 :
775 : /************************************************************************/
776 : /* GetIODetails() */
777 : /************************************************************************/
778 :
779 185 : void CPCIDSKFile::GetIODetails( void ***io_handle_pp,
780 : Mutex ***io_mutex_pp,
781 : std::string filename,
782 : bool writable )
783 :
784 : {
785 185 : *io_handle_pp = NULL;
786 185 : *io_mutex_pp = NULL;
787 :
788 : /* -------------------------------------------------------------------- */
789 : /* Does this reference the PCIDSK file itself? */
790 : /* -------------------------------------------------------------------- */
791 185 : if( filename.size() == 0 )
792 : {
793 183 : *io_handle_pp = &io_handle;
794 183 : *io_mutex_pp = &io_mutex;
795 183 : return;
796 : }
797 :
798 : /* -------------------------------------------------------------------- */
799 : /* Does the file exist already in our file list? */
800 : /* -------------------------------------------------------------------- */
801 : unsigned int i;
802 :
803 2 : for( i = 0; i < file_list.size(); i++ )
804 : {
805 0 : if( file_list[i].filename == filename
806 : && (!writable || file_list[i].writable) )
807 : {
808 0 : *io_handle_pp = &(file_list[i].io_handle);
809 0 : *io_mutex_pp = &(file_list[i].io_mutex);
810 0 : return;
811 : }
812 : }
813 :
814 : /* -------------------------------------------------------------------- */
815 : /* If not, we need to try and open the file. Eventually we */
816 : /* will need better rules about read or update access. */
817 : /* -------------------------------------------------------------------- */
818 2 : ProtectedFile new_file;
819 :
820 2 : if( writable )
821 1 : new_file.io_handle = interfaces.io->Open( filename, "r+" );
822 : else
823 1 : new_file.io_handle = interfaces.io->Open( filename, "r" );
824 :
825 2 : if( new_file.io_handle == NULL )
826 : ThrowPCIDSKException( "Unable to open file '%s'.",
827 0 : filename.c_str() );
828 :
829 : /* -------------------------------------------------------------------- */
830 : /* Push the new file into the list of files managed for this */
831 : /* PCIDSK file. */
832 : /* -------------------------------------------------------------------- */
833 2 : new_file.io_mutex = interfaces.CreateMutex();
834 2 : new_file.filename = filename;
835 2 : new_file.writable = writable;
836 :
837 2 : file_list.push_back( new_file );
838 :
839 2 : *io_handle_pp = &(file_list[file_list.size()-1].io_handle);
840 2 : *io_mutex_pp = &(file_list[file_list.size()-1].io_mutex);
841 : }
842 :
843 : /************************************************************************/
844 : /* DeleteSegment() */
845 : /************************************************************************/
846 :
847 1 : void CPCIDSKFile::DeleteSegment( int segment )
848 :
849 : {
850 : /* -------------------------------------------------------------------- */
851 : /* Is this an existing segment? */
852 : /* -------------------------------------------------------------------- */
853 1 : PCIDSKSegment *poSeg = GetSegment( segment );
854 :
855 1 : if( poSeg == NULL )
856 0 : ThrowPCIDSKException( "DeleteSegment(%d) failed, segment does not exist.", segment );
857 :
858 : /* -------------------------------------------------------------------- */
859 : /* Wipe associated metadata. */
860 : /* -------------------------------------------------------------------- */
861 1 : std::vector<std::string> md_keys = poSeg->GetMetadataKeys();
862 : unsigned int i;
863 :
864 2 : for( i = 0; i < md_keys.size(); i++ )
865 0 : poSeg->SetMetadataValue( md_keys[i], "" );
866 :
867 : /* -------------------------------------------------------------------- */
868 : /* Remove the segment object from the segment object cache. I */
869 : /* hope the application is not retaining any references to this */
870 : /* segment! */
871 : /* -------------------------------------------------------------------- */
872 1 : segments[segment] = NULL;
873 1 : delete poSeg;
874 :
875 : /* -------------------------------------------------------------------- */
876 : /* Mark the segment pointer as deleted. */
877 : /* -------------------------------------------------------------------- */
878 1 : segment_pointers.buffer[(segment-1)*32] = 'D';
879 :
880 : // write the updated segment pointer back to the file.
881 : WriteToFile( segment_pointers.buffer + (segment-1)*32,
882 : segment_pointers_offset + (segment-1)*32,
883 1 : 32 );
884 1 : }
885 :
886 : /************************************************************************/
887 : /* CreateSegment() */
888 : /************************************************************************/
889 :
890 90 : int CPCIDSKFile::CreateSegment( std::string name, std::string description,
891 : eSegType seg_type, int data_blocks )
892 :
893 : {
894 : /* -------------------------------------------------------------------- */
895 : /* Set the size of fixed length segments. */
896 : /* -------------------------------------------------------------------- */
897 90 : int expected_data_blocks = 0;
898 90 : bool prezero = false;
899 :
900 90 : switch( seg_type )
901 : {
902 : case SEG_LUT:
903 0 : expected_data_blocks = 2;
904 0 : break;
905 :
906 : case SEG_PCT:
907 1 : expected_data_blocks = 6;
908 1 : break;
909 :
910 : case SEG_SIG:
911 0 : expected_data_blocks = 12;
912 0 : break;
913 :
914 : case SEG_GCP2:
915 : // expected_data_blocks = 67;
916 : // Change seg type to new GCP segment type
917 0 : expected_data_blocks = 129;
918 0 : break;
919 :
920 : case SEG_GEO:
921 52 : expected_data_blocks = 6;
922 52 : break;
923 :
924 : case SEG_TEX:
925 0 : expected_data_blocks = 64;
926 0 : prezero = true;
927 0 : break;
928 :
929 : case SEG_BIT:
930 : {
931 0 : uint64 bytes = ((width * (uint64) height) + 7) / 8;
932 0 : expected_data_blocks = (int) ((bytes + 511) / 512);
933 0 : prezero = true;
934 : }
935 : break;
936 :
937 : default:
938 : break;
939 : }
940 :
941 90 : if( data_blocks == 0 && expected_data_blocks != 0 )
942 1 : data_blocks = expected_data_blocks;
943 :
944 : /* -------------------------------------------------------------------- */
945 : /* Find an empty Segment Pointer. For System segments we start */
946 : /* at the end, instead of the beginning to avoid using up */
947 : /* segment numbers that the user would notice. */
948 : /* -------------------------------------------------------------------- */
949 90 : int segment = 1;
950 90 : int64 seg_start = -1;
951 90 : PCIDSKBuffer segptr( 32 );
952 :
953 90 : if( seg_type == SEG_SYS )
954 : {
955 42 : for( segment=segment_count; segment >= 1; segment-- )
956 : {
957 42 : memcpy( segptr.buffer, segment_pointers.buffer+(segment-1)*32, 32);
958 :
959 42 : uint64 this_seg_size = segptr.GetUInt64(23,9);
960 42 : char flag = (char) segptr.buffer[0];
961 :
962 42 : if( flag == 'D'
963 : && (uint64) data_blocks+2 == this_seg_size
964 : && this_seg_size > 0 )
965 0 : seg_start = segptr.GetUInt64(12,11) - 1;
966 42 : else if( flag == ' ' )
967 30 : seg_start = 0;
968 12 : else if( flag && this_seg_size == 0 )
969 0 : seg_start = 0;
970 :
971 42 : if( seg_start != -1 )
972 30 : break;
973 : }
974 : }
975 : else
976 : {
977 83 : for( segment=1; segment <= segment_count; segment++ )
978 : {
979 83 : memcpy( segptr.buffer, segment_pointers.buffer+(segment-1)*32, 32);
980 :
981 83 : uint64 this_seg_size = segptr.GetUInt64(23,9);
982 83 : char flag = (char) segptr.buffer[0];
983 :
984 83 : if( flag == 'D'
985 : && (uint64) data_blocks+2 == this_seg_size
986 : && this_seg_size > 0 )
987 0 : seg_start = segptr.GetUInt64(12,11) - 1;
988 83 : else if( flag == ' ' )
989 60 : seg_start = 0;
990 23 : else if( flag && this_seg_size == 0 )
991 0 : seg_start = 0;
992 :
993 83 : if( seg_start != -1 )
994 60 : break;
995 : }
996 : }
997 :
998 90 : if( segment > segment_count )
999 0 : ThrowPCIDSKException( "All %d segment pointers in use.", segment_count);
1000 :
1001 : /* -------------------------------------------------------------------- */
1002 : /* If the segment does not have a data area already, identify */
1003 : /* it's location at the end of the file, and extend the file to */
1004 : /* the desired length. */
1005 : /* -------------------------------------------------------------------- */
1006 90 : if( seg_start == 0 )
1007 : {
1008 90 : seg_start = GetFileSize();
1009 90 : ExtendFile( data_blocks + 2, prezero );
1010 : }
1011 :
1012 : /* -------------------------------------------------------------------- */
1013 : /* Update the segment pointer information. */
1014 : /* -------------------------------------------------------------------- */
1015 : // SP1.1 - Flag
1016 90 : segptr.Put( "A", 0, 1 );
1017 :
1018 : // SP1.2 - Type
1019 90 : segptr.Put( (int) seg_type, 1, 3 );
1020 :
1021 : // SP1.3 - Name
1022 90 : segptr.Put( name.c_str(), 4, 8 );
1023 :
1024 : // SP1.4 - start block
1025 90 : segptr.Put( (uint64) (seg_start + 1), 12, 11 );
1026 :
1027 : // SP1.5 - data blocks.
1028 90 : segptr.Put( data_blocks+2, 23, 9 );
1029 :
1030 : // Update in memory copy of segment pointers.
1031 90 : memcpy( segment_pointers.buffer+(segment-1)*32, segptr.buffer, 32);
1032 :
1033 : // Update on disk.
1034 : WriteToFile( segptr.buffer,
1035 90 : segment_pointers_offset + (segment-1)*32, 32 );
1036 :
1037 : /* -------------------------------------------------------------------- */
1038 : /* Prepare segment header. */
1039 : /* -------------------------------------------------------------------- */
1040 90 : PCIDSKBuffer sh(1024);
1041 :
1042 : char current_time[17];
1043 :
1044 90 : GetCurrentDateTime( current_time );
1045 :
1046 90 : sh.Put( " ", 0, 1024 );
1047 :
1048 : // SH1 - segment content description
1049 90 : sh.Put( description.c_str(), 0, 64 );
1050 :
1051 : // SH3 - Creation time/date
1052 90 : sh.Put( current_time, 128, 16 );
1053 :
1054 : // SH4 - Last Update time/date
1055 90 : sh.Put( current_time, 144, 16 );
1056 :
1057 : /* -------------------------------------------------------------------- */
1058 : /* Write segment header. */
1059 : /* -------------------------------------------------------------------- */
1060 90 : WriteToFile( sh.buffer, seg_start * 512, 1024 );
1061 :
1062 : /* -------------------------------------------------------------------- */
1063 : /* Initialize the newly created segment. */
1064 : /* -------------------------------------------------------------------- */
1065 90 : PCIDSKSegment *seg_obj = GetSegment( segment );
1066 :
1067 90 : seg_obj->Initialize();
1068 :
1069 90 : return segment;
1070 : }
1071 :
1072 : /************************************************************************/
1073 : /* ExtendFile() */
1074 : /************************************************************************/
1075 :
1076 139 : void CPCIDSKFile::ExtendFile( uint64 blocks_requested, bool prezero )
1077 :
1078 : {
1079 139 : if( prezero )
1080 : {
1081 5 : std::vector<uint8> zeros;
1082 5 : uint64 blocks_to_zero = blocks_requested;
1083 :
1084 5 : zeros.resize( 512 * 32 );
1085 :
1086 43 : while( blocks_to_zero > 0 )
1087 : {
1088 33 : uint64 this_time = blocks_to_zero;
1089 33 : if( this_time > 32 )
1090 28 : this_time = 32;
1091 :
1092 33 : WriteToFile( &(zeros[0]), file_size * 512, this_time*512 );
1093 33 : blocks_to_zero -= this_time;
1094 33 : file_size += this_time;
1095 5 : }
1096 : }
1097 : else
1098 : {
1099 134 : WriteToFile( "\0", (file_size + blocks_requested) * 512 - 1, 1 );
1100 134 : file_size += blocks_requested;
1101 : }
1102 :
1103 139 : PCIDSKBuffer fh3( 16 );
1104 139 : fh3.Put( file_size, 0, 16 );
1105 139 : WriteToFile( fh3.buffer, 16, 16 );
1106 139 : }
1107 :
1108 : /************************************************************************/
1109 : /* ExtendSegment() */
1110 : /************************************************************************/
1111 :
1112 42 : void CPCIDSKFile::ExtendSegment( int segment, uint64 blocks_requested,
1113 : bool prezero )
1114 :
1115 : {
1116 : // for now we take it for granted that the segment is valid and at th
1117 : // end of the file - later we should support moving it.
1118 :
1119 42 : ExtendFile( blocks_requested, prezero );
1120 :
1121 : // Update the block count.
1122 : segment_pointers.Put(
1123 : segment_pointers.GetUInt64((segment-1)*32+23,9) + blocks_requested,
1124 42 : (segment-1)*32+23, 9 );
1125 :
1126 : // write the updated segment pointer back to the file.
1127 : WriteToFile( segment_pointers.buffer + (segment-1)*32,
1128 : segment_pointers_offset + (segment-1)*32,
1129 42 : 32 );
1130 42 : }
1131 :
1132 : /************************************************************************/
1133 : /* MoveSegmentToEOF() */
1134 : /************************************************************************/
1135 :
1136 7 : void CPCIDSKFile::MoveSegmentToEOF( int segment )
1137 :
1138 : {
1139 7 : int segptr_off = (segment - 1) * 32;
1140 : uint64 seg_start, seg_size;
1141 : uint64 new_seg_start;
1142 :
1143 7 : seg_start = segment_pointers.GetUInt64( segptr_off + 12, 11 );
1144 7 : seg_size = segment_pointers.GetUInt64( segptr_off + 23, 9 );
1145 :
1146 : // Are we already at the end of the file?
1147 7 : if( (seg_start + seg_size - 1) == file_size )
1148 0 : return;
1149 :
1150 7 : new_seg_start = file_size + 1;
1151 :
1152 : // Grow the file to hold the segment at the end.
1153 7 : ExtendFile( seg_size, false );
1154 :
1155 : // Move the segment data to the new location.
1156 : uint8 copy_buf[16384];
1157 : uint64 srcoff, dstoff, bytes_to_go;
1158 :
1159 7 : bytes_to_go = seg_size * 512;
1160 7 : srcoff = (seg_start - 1) * 512;
1161 7 : dstoff = (new_seg_start - 1) * 512;
1162 :
1163 21 : while( bytes_to_go > 0 )
1164 : {
1165 7 : uint64 bytes_this_chunk = sizeof(copy_buf);
1166 7 : if( bytes_to_go < bytes_this_chunk )
1167 7 : bytes_this_chunk = bytes_to_go;
1168 :
1169 7 : ReadFromFile( copy_buf, srcoff, bytes_this_chunk );
1170 7 : WriteToFile( copy_buf, dstoff, bytes_this_chunk );
1171 :
1172 7 : srcoff += bytes_this_chunk;
1173 7 : dstoff += bytes_this_chunk;
1174 7 : bytes_to_go -= bytes_this_chunk;
1175 : }
1176 :
1177 : // Update segment pointer in memory and on disk.
1178 7 : segment_pointers.Put( new_seg_start, segptr_off + 12, 11 );
1179 :
1180 : WriteToFile( segment_pointers.buffer + segptr_off,
1181 : segment_pointers_offset + segptr_off,
1182 7 : 32 );
1183 :
1184 : // Update the segments own information.
1185 7 : if( segments[segment] != NULL )
1186 : {
1187 : CPCIDSKSegment *seg =
1188 7 : dynamic_cast<CPCIDSKSegment *>( segments[segment] );
1189 :
1190 7 : seg->LoadSegmentPointer( segment_pointers.buffer + segptr_off );
1191 : }
1192 : }
1193 :
1194 : /************************************************************************/
1195 : /* CreateOverviews() */
1196 : /************************************************************************/
1197 : /*
1198 : const char *pszResampling;
1199 : Can be "NEAREST" for Nearest Neighbour resampling (the fastest),
1200 : "AVERAGE" for block averaging or "MODE" for block mode. This
1201 : establishing the type of resampling to be applied when preparing
1202 : the decimated overviews. Other methods can be set as well, but
1203 : not all applications might support a given overview generation
1204 : method.
1205 : */
1206 :
1207 1 : void CPCIDSKFile::CreateOverviews( int chan_count, int *chan_list,
1208 : int factor, std::string resampling )
1209 :
1210 : {
1211 1 : std::vector<int> default_chan_list;
1212 :
1213 : /* -------------------------------------------------------------------- */
1214 : /* Default to processing all bands. */
1215 : /* -------------------------------------------------------------------- */
1216 1 : if( chan_count == 0 )
1217 : {
1218 0 : chan_count = channel_count;
1219 0 : default_chan_list.resize( chan_count );
1220 :
1221 0 : for( int i = 0; i < chan_count; i++ )
1222 0 : default_chan_list[i] = i+1;
1223 :
1224 0 : chan_list = &(default_chan_list[0]);
1225 : }
1226 :
1227 : /* -------------------------------------------------------------------- */
1228 : /* Work out the creation options that should apply for the */
1229 : /* overview. */
1230 : /* -------------------------------------------------------------------- */
1231 1 : std::string layout = GetMetadataValue( "_DBLayout" );
1232 1 : int blocksize = 127;
1233 2 : std::string compression = "NONE";
1234 :
1235 2 : if( strncmp( layout.c_str(), "TILED", 5 ) == 0 )
1236 : {
1237 0 : ParseTileFormat( layout, blocksize, compression );
1238 : }
1239 :
1240 : /* -------------------------------------------------------------------- */
1241 : /* Make sure we have a blockmap segment for managing the tiled */
1242 : /* layers. */
1243 : /* -------------------------------------------------------------------- */
1244 1 : PCIDSKSegment *bm_seg = GetSegment( SEG_SYS, "SysBMDir" );
1245 : SysBlockMap *bm;
1246 :
1247 1 : if( bm_seg == NULL )
1248 : {
1249 : CreateSegment( "SysBMDir",
1250 : "System Block Map Directory - Do not modify.",
1251 1 : SEG_SYS, 0 );
1252 2 : bm_seg = GetSegment( SEG_SYS, "SysBMDir" );
1253 1 : bm = dynamic_cast<SysBlockMap *>(bm_seg);
1254 1 : bm->Initialize();
1255 : }
1256 : else
1257 0 : bm = dynamic_cast<SysBlockMap *>(bm_seg);
1258 :
1259 : /* ==================================================================== */
1260 : /* Loop over the channels. */
1261 : /* ==================================================================== */
1262 2 : for( int chan_index = 0; chan_index < chan_count; chan_index++ )
1263 : {
1264 1 : int channel_number = chan_list[chan_index];
1265 1 : PCIDSKChannel *channel = GetChannel( channel_number );
1266 :
1267 : /* -------------------------------------------------------------------- */
1268 : /* Figure out if the given overview level already exists */
1269 : /* for a given channel; if it does, skip creating it. */
1270 : /* -------------------------------------------------------------------- */
1271 1 : bool overview_exists = false;
1272 1 : for( int i = channel->GetOverviewCount()-1; i >= 0; i-- )
1273 : {
1274 0 : PCIDSKChannel *overview = channel->GetOverview( i );
1275 :
1276 0 : if( overview->GetWidth() == channel->GetWidth() / factor
1277 0 : && overview->GetHeight() == channel->GetHeight() / factor )
1278 : {
1279 0 : overview_exists = true;
1280 : }
1281 : }
1282 :
1283 1 : if (overview_exists == false)
1284 : {
1285 : /* -------------------------------------------------------------------- */
1286 : /* Create the overview as a tiled image layer. */
1287 : /* -------------------------------------------------------------------- */
1288 : int virtual_image =
1289 1 : bm->CreateVirtualImageFile( channel->GetWidth() / factor,
1290 1 : channel->GetHeight() / factor,
1291 : blocksize, blocksize,
1292 3 : channel->GetType(), compression );
1293 :
1294 : /* -------------------------------------------------------------------- */
1295 : /* Attach reference to this overview as metadata. */
1296 : /* -------------------------------------------------------------------- */
1297 : char overview_md_value[128];
1298 : char overview_md_key[128];
1299 :
1300 1 : sprintf( overview_md_key, "_Overview_%d", factor );
1301 1 : sprintf( overview_md_value, "%d 0 %s",virtual_image,resampling.c_str());
1302 :
1303 1 : channel->SetMetadataValue( overview_md_key, overview_md_value );
1304 : }
1305 :
1306 : /* -------------------------------------------------------------------- */
1307 : /* Force channel to invalidate it's loaded overview list. */
1308 : /* -------------------------------------------------------------------- */
1309 1 : dynamic_cast<CPCIDSKChannel *>(channel)->InvalidateOverviewInfo();
1310 1 : }
1311 2140 : }
1312 :
|