Line data Source code
1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the Create() function to create new PCIDSK files.
4 : *
5 : ******************************************************************************
6 : * Copyright (c) 2009
7 : * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
8 : *
9 : * SPDX-License-Identifier: MIT
10 : ****************************************************************************/
11 : #include "pcidsk.h"
12 : #include "pcidsk_config.h"
13 : #include "pcidsk_types.h"
14 : #include "pcidsk_exception.h"
15 : #include "pcidsk_file.h"
16 : #include "pcidsk_georef.h"
17 : #include "core/pcidsk_utils.h"
18 : #include "core/cpcidskblockfile.h"
19 : #include "core/clinksegment.h"
20 : #include "segment/systiledir.h"
21 : #include <cassert>
22 : #include <cstdlib>
23 : #include <cstring>
24 : #include <cstdio>
25 : #include <sstream>
26 : #include <iomanip>
27 : #include <memory>
28 :
29 : using namespace PCIDSK;
30 :
31 : /************************************************************************/
32 : /* Create() */
33 : /************************************************************************/
34 :
35 : /**
36 : * Create a PCIDSK (.pix) file.
37 : *
38 : * @param filename the name of the PCIDSK file to create.
39 : * @param pixels the width of the new file in pixels.
40 : * @param lines the height of the new file in scanlines.
41 : * @param channel_count the number of channels to create.
42 : * @param channel_types an array of types for all the channels, or NULL for
43 : * all CHN_8U channels.
44 : * @param options creation options (interleaving, etc)
45 : * @param interfaces Either NULL to use default interfaces, or a pointer
46 : * to a populated interfaces object.
47 : *
48 : * @return a pointer to a file object for accessing the PCIDSK file.
49 : */
50 :
51 : PCIDSKFile PCIDSK_DLL *
52 123 : PCIDSK::Create( const std::string& filename, int pixels, int lines,
53 : int channel_count, eChanType *channel_types,
54 : const std::string& oOrigOptions, const PCIDSKInterfaces *interfaces )
55 :
56 : {
57 123 : if( pixels < 0 || pixels > 99999999 ||
58 123 : lines < 0 || lines > 99999999 ||
59 123 : channel_count < 0 || channel_count > 99999999 )
60 : {
61 0 : return (PCIDSKFile*)ThrowPCIDSKExceptionPtr(
62 0 : "PCIDSK::Create(): invalid dimensions / band count." );
63 : }
64 :
65 : /* -------------------------------------------------------------------- */
66 : /* Use default interfaces if none are passed in. */
67 : /* -------------------------------------------------------------------- */
68 123 : PCIDSKInterfaces default_interfaces;
69 123 : if( interfaces == nullptr )
70 0 : interfaces = &default_interfaces;
71 :
72 : /* -------------------------------------------------------------------- */
73 : /* Default the channel types to all 8U if not provided. */
74 : /* -------------------------------------------------------------------- */
75 246 : std::vector<eChanType> default_channel_types;
76 :
77 123 : if( channel_types == nullptr )
78 : {
79 0 : default_channel_types.resize( channel_count+1, CHN_8U );
80 0 : channel_types = &(default_channel_types[0]);
81 : }
82 :
83 : /* -------------------------------------------------------------------- */
84 : /* Validate parameters. */
85 : /* -------------------------------------------------------------------- */
86 123 : const char *interleaving = nullptr;
87 246 : std::string compression = "NONE";
88 123 : bool nocreate = false;
89 123 : int tilesize = PCIDSK_DEFAULT_TILE_SIZE;
90 246 : std::string oLinkFilename;
91 :
92 246 : std::string options = oOrigOptions;
93 123 : UCaseStr( options );
94 679 : for(auto & c : options)
95 : {
96 556 : if(c == ',')
97 0 : c = ' ';
98 : }
99 :
100 : //The code down below assumes that the interleaving
101 : //will be first in the string, so let's make sure
102 : //that that is true
103 123 : auto apszInterleavingOptions =
104 123 : {"FILE", "PIXEL", "BAND", "TILED", "NOZERO"};
105 374 : for(auto pszInterleavingOption : apszInterleavingOptions)
106 : {
107 374 : std::size_t nPos = options.find(pszInterleavingOption);
108 374 : if(nPos > 0 && nPos < options.size())
109 : {
110 0 : std::size_t nInterleavingStart = nPos;
111 : //Some options are more than just this string
112 : //so we cannot take strlen(pszInterleavingOption) as the
113 : //endpoint of the option.
114 0 : std::size_t nInterleavingEnd = options.find(" ", nPos);
115 0 : if(nInterleavingEnd == std::string::npos)
116 0 : nInterleavingEnd = options.size();
117 : std::string sSubstring =
118 : options.substr(nInterleavingStart,
119 0 : nInterleavingEnd - nInterleavingStart);
120 0 : options.erase(options.begin() + nInterleavingStart,
121 0 : options.begin() + nInterleavingEnd);
122 0 : options = std::move(sSubstring) + ' ' + std::move(options);
123 0 : break;
124 : }
125 374 : else if(nPos == 0)
126 123 : break;
127 : }
128 :
129 123 : if(STARTS_WITH(options.c_str(), "PIXEL") )
130 0 : interleaving = "PIXEL";
131 123 : else if( STARTS_WITH(options.c_str(), "BAND") )
132 115 : interleaving = "BAND";
133 8 : else if( STARTS_WITH(options.c_str(), "TILED") )
134 : {
135 7 : interleaving = "FILE";
136 7 : ParseTileFormat( options, tilesize, compression );
137 : }
138 1 : else if(STARTS_WITH(options.c_str(), "NOZERO"))
139 : {
140 0 : interleaving = "BAND";
141 : }
142 1 : else if( STARTS_WITH(options.c_str(), "FILE") )
143 : {
144 1 : if( STARTS_WITH(options.c_str(), "FILENOCREATE") )
145 : {
146 0 : nocreate = true;
147 0 : oLinkFilename = ParseLinkedFilename(oOrigOptions);
148 : }
149 1 : interleaving = "FILE";
150 : }
151 : else
152 0 : return (PCIDSKFile*)ThrowPCIDSKExceptionPtr( "PCIDSK::Create() options '%s' not recognised.",
153 0 : options.c_str() );
154 :
155 123 : bool nozero = options.find("NOZERO") != std::string::npos;
156 :
157 : /* -------------------------------------------------------------------- */
158 : /* Validate the channel types. */
159 : /* -------------------------------------------------------------------- */
160 123 : int16 channels[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
161 : int chan_index;
162 123 : bool regular = true;
163 :
164 249 : for( chan_index=0; chan_index < channel_count; chan_index++ )
165 : {
166 126 : if( chan_index > 0
167 46 : && ((int) channel_types[chan_index])
168 46 : < ((int) channel_types[chan_index-1]) )
169 0 : regular = false;
170 :
171 126 : channels[((int) channel_types[chan_index])]++;
172 : }
173 :
174 123 : if( !regular && strcmp(interleaving,"FILE") != 0 )
175 : {
176 0 : return (PCIDSKFile*)ThrowPCIDSKExceptionPtr(
177 : "The order of the channel types is not valid for interleaving=%s. "
178 : "Channels must be packed in the following order: "
179 : "8U, 16S, 16U, 32S, 32U, 32R, 64S, 64U, 64R, C16S, C16U, C32S, C32U, C32R",
180 0 : interleaving);
181 : }
182 :
183 : /* -------------------------------------------------------------------- */
184 : /* Create the file. */
185 : /* -------------------------------------------------------------------- */
186 131 : void *io_handle = interfaces->io->Open( filename, "w+" );
187 :
188 119 : assert( io_handle != nullptr );
189 :
190 : /* -------------------------------------------------------------------- */
191 : /* Use the following structure instead of a try / catch. */
192 : /* -------------------------------------------------------------------- */
193 : struct IOHandleAutoPtr
194 : {
195 : const PCIDSKInterfaces * interfaces;
196 : void * io_handle;
197 :
198 119 : IOHandleAutoPtr(const PCIDSKInterfaces * interfacesIn,
199 : void * io_handleIn)
200 119 : : interfaces(interfacesIn),
201 119 : io_handle(io_handleIn)
202 : {
203 119 : }
204 119 : ~IOHandleAutoPtr()
205 119 : {
206 119 : Close();
207 119 : }
208 238 : void Close()
209 : {
210 238 : if (interfaces && io_handle)
211 119 : interfaces->io->Close(io_handle);
212 :
213 238 : io_handle = nullptr;
214 238 : }
215 : };
216 :
217 238 : IOHandleAutoPtr oHandleAutoPtr(interfaces, io_handle);
218 :
219 : /* ==================================================================== */
220 : /* Establish some key file layout information. */
221 : /* ==================================================================== */
222 119 : int image_header_start = 1; // in blocks
223 119 : uint64 image_data_start, image_data_size=0; // in blocks
224 119 : uint64 segment_ptr_start, segment_ptr_size=64; // in blocks
225 : int pixel_group_size, line_size; // in bytes
226 119 : int image_header_count = channel_count;
227 :
228 : /* -------------------------------------------------------------------- */
229 : /* Pixel interleaved. */
230 : /* -------------------------------------------------------------------- */
231 119 : if( strcmp(interleaving,"PIXEL") == 0 )
232 : {
233 0 : pixel_group_size =
234 0 : channels[CHN_8U] * DataTypeSize(CHN_8U) +
235 0 : channels[CHN_16S] * DataTypeSize(CHN_16S) +
236 0 : channels[CHN_16U] * DataTypeSize(CHN_16U) +
237 0 : channels[CHN_32S] * DataTypeSize(CHN_32S) +
238 0 : channels[CHN_32U] * DataTypeSize(CHN_32U) +
239 0 : channels[CHN_32R] * DataTypeSize(CHN_32R) +
240 0 : channels[CHN_64S] * DataTypeSize(CHN_64S) +
241 0 : channels[CHN_64U] * DataTypeSize(CHN_64U) +
242 0 : channels[CHN_64R] * DataTypeSize(CHN_64R) +
243 0 : channels[CHN_C16S] * DataTypeSize(CHN_C16S) +
244 0 : channels[CHN_C16U] * DataTypeSize(CHN_C16U) +
245 0 : channels[CHN_C32S] * DataTypeSize(CHN_C32S) +
246 0 : channels[CHN_C32U] * DataTypeSize(CHN_C32U) +
247 0 : channels[CHN_C32R] * DataTypeSize(CHN_C32R);
248 0 : line_size = ((pixel_group_size * pixels + 511) / 512) * 512;
249 0 : image_data_size = (((uint64)line_size) * lines) / 512;
250 :
251 : // TODO: Old code enforces a 1TB limit for some reason.
252 : }
253 :
254 : /* -------------------------------------------------------------------- */
255 : /* Band interleaved. */
256 : /* -------------------------------------------------------------------- */
257 119 : else if( strcmp(interleaving,"BAND") == 0 )
258 : {
259 111 : pixel_group_size =
260 111 : channels[CHN_8U] * DataTypeSize(CHN_8U) +
261 111 : channels[CHN_16S] * DataTypeSize(CHN_16S) +
262 111 : channels[CHN_16U] * DataTypeSize(CHN_16U) +
263 111 : channels[CHN_32S] * DataTypeSize(CHN_32S) +
264 111 : channels[CHN_32U] * DataTypeSize(CHN_32U) +
265 111 : channels[CHN_32R] * DataTypeSize(CHN_32R) +
266 111 : channels[CHN_64S] * DataTypeSize(CHN_64S) +
267 111 : channels[CHN_64U] * DataTypeSize(CHN_64U) +
268 111 : channels[CHN_64R] * DataTypeSize(CHN_64R) +
269 111 : channels[CHN_C16S] * DataTypeSize(CHN_C16S) +
270 111 : channels[CHN_C16U] * DataTypeSize(CHN_C16U) +
271 111 : channels[CHN_C32S] * DataTypeSize(CHN_C32S) +
272 111 : channels[CHN_C32U] * DataTypeSize(CHN_C32U) +
273 111 : channels[CHN_C32R] * DataTypeSize(CHN_C32R);
274 : // BAND interleaved bands are tightly packed.
275 111 : image_data_size =
276 111 : (((uint64)pixel_group_size) * pixels * lines + 511) / 512;
277 :
278 : // TODO: Old code enforces a 1TB limit for some reason.
279 : }
280 :
281 : /* -------------------------------------------------------------------- */
282 : /* FILE/Tiled. */
283 : /* -------------------------------------------------------------------- */
284 8 : else if( strcmp(interleaving,"FILE") == 0 )
285 : {
286 : // For some reason we reserve extra space, but only for FILE.
287 8 : if( channel_count < 64 )
288 8 : image_header_count = 64;
289 :
290 8 : image_data_size = 0;
291 :
292 : // TODO: Old code enforces a 1TB limit on the fattest band.
293 : }
294 :
295 : /* -------------------------------------------------------------------- */
296 : /* Place components. */
297 : /* -------------------------------------------------------------------- */
298 119 : segment_ptr_start = image_header_start + image_header_count*2;
299 119 : image_data_start = segment_ptr_start + segment_ptr_size;
300 :
301 : /* ==================================================================== */
302 : /* Prepare the file header. */
303 : /* ==================================================================== */
304 238 : PCIDSKBuffer fh(512);
305 :
306 : char current_time[17];
307 119 : GetCurrentDateTime( current_time );
308 :
309 : // Initialize everything to spaces.
310 119 : fh.Put( "", 0, 512 );
311 :
312 : /* -------------------------------------------------------------------- */
313 : /* File Type, Version, and Size */
314 : /* Notice: we get the first 4 characters from PCIVERSIONAME. */
315 : /* -------------------------------------------------------------------- */
316 : // FH1 - magic format string.
317 119 : fh.Put( "PCIDSK", 0, 8 );
318 :
319 : // FH2 - TODO: Allow caller to pass this in.
320 119 : fh.Put( "SDK V1.0", 8, 8 );
321 :
322 : // FH3 - file size later.
323 119 : fh.Put( (image_data_start + image_data_size), 16, 16 );
324 :
325 : // FH4 - 16 characters reserved - spaces.
326 :
327 : // FH5 - Description
328 119 : fh.Put( filename.c_str(), 48, 64 );
329 :
330 : // FH6 - Facility
331 119 : fh.Put( "PCI Geomatics, Markham, Canada.", 112, 32 );
332 :
333 : // FH7.1 / FH7.2 - left blank (64+64 bytes @ 144)
334 :
335 : // FH8 Creation date/time
336 119 : fh.Put( current_time, 272, 16 );
337 :
338 : // FH9 Update date/time
339 119 : fh.Put( current_time, 288, 16 );
340 :
341 : /* -------------------------------------------------------------------- */
342 : /* Image Data */
343 : /* -------------------------------------------------------------------- */
344 : // FH10 - start block of image data
345 119 : fh.Put( image_data_start+1, 304, 16 );
346 :
347 : // FH11 - number of blocks of image data.
348 119 : fh.Put( image_data_size, 320, 16 );
349 :
350 : // FH12 - start block of image headers.
351 119 : fh.Put( image_header_start+1, 336, 16 );
352 :
353 : // FH13 - number of blocks of image headers.
354 119 : fh.Put( image_header_count*2, 352, 8);
355 :
356 : // FH14 - interleaving.
357 119 : fh.Put( interleaving, 360, 8);
358 :
359 : // FH15 - reserved - MIXED is for some ancient backwards compatibility.
360 119 : fh.Put( "MIXED", 368, 8);
361 :
362 : // FH16 - number of image bands.
363 119 : fh.Put( channel_count, 376, 8 );
364 :
365 : // FH17 - width of image in pixels.
366 119 : fh.Put( pixels, 384, 8 );
367 :
368 : // FH18 - height of image in pixels.
369 119 : fh.Put( lines, 392, 8 );
370 :
371 : // FH19 - pixel ground size interpretation.
372 119 : fh.Put( "METRE", 400, 8 );
373 :
374 : // TODO:
375 : //PrintDouble( fh->XPixelSize, "%16.9f", 1.0 );
376 : //PrintDouble( fh->YPixelSize, "%16.9f", 1.0 );
377 119 : fh.Put( "1.0", 408, 16 );
378 119 : fh.Put( "1.0", 424, 16 );
379 :
380 : /* -------------------------------------------------------------------- */
381 : /* Segment Pointers */
382 : /* -------------------------------------------------------------------- */
383 : // FH22 - start block of segment pointers.
384 119 : fh.Put( segment_ptr_start+1, 440, 16 );
385 :
386 : // fH23 - number of blocks of segment pointers.
387 119 : fh.Put( segment_ptr_size, 456, 8 );
388 :
389 : /* -------------------------------------------------------------------- */
390 : /* Number of different types of Channels */
391 : /* -------------------------------------------------------------------- */
392 : // FH24.1 - 8U bands.
393 119 : fh.Put( channels[CHN_8U], 464, 4 );
394 :
395 : // FH24.2 - 16S bands.
396 119 : fh.Put( channels[CHN_16S], 468, 4 );
397 :
398 : // FH24.3 - 16U bands.
399 119 : fh.Put( channels[CHN_16U], 472, 4 );
400 :
401 : // FH24.4 - 32R bands.
402 119 : fh.Put( channels[CHN_32R], 476, 4 );
403 :
404 : // FH24.5 - C16U bands
405 119 : fh.Put( channels[CHN_C16U], 480, 4 );
406 :
407 : // FH24.6 - C16S bands
408 119 : fh.Put( channels[CHN_C16S], 484, 4 );
409 :
410 : // FH24.7 - C32R bands
411 119 : fh.Put( channels[CHN_C32R], 488, 4 );
412 :
413 119 : if (!BigEndianSystem())
414 : {
415 119 : SwapData(channels + CHN_32S, 2, 1);
416 119 : SwapData(channels + CHN_32U, 2, 1);
417 119 : SwapData(channels + CHN_64S, 2, 1);
418 119 : SwapData(channels + CHN_64U, 2, 1);
419 119 : SwapData(channels + CHN_64R, 2, 1);
420 119 : SwapData(channels + CHN_C32S, 2, 1);
421 119 : SwapData(channels + CHN_C32U, 2, 1);
422 : }
423 :
424 119 : fh.PutBin(channels[CHN_32S], 492);
425 119 : fh.PutBin(channels[CHN_32U], 494);
426 119 : fh.PutBin(channels[CHN_64S], 496);
427 119 : fh.PutBin(channels[CHN_64U], 498);
428 119 : fh.PutBin(channels[CHN_64R], 500);
429 119 : fh.PutBin(channels[CHN_C32S], 502);
430 119 : fh.PutBin(channels[CHN_C32U], 504);
431 :
432 : /* -------------------------------------------------------------------- */
433 : /* Write out the file header. */
434 : /* -------------------------------------------------------------------- */
435 119 : interfaces->io->Write( fh.buffer, 512, 1, io_handle );
436 :
437 : /* ==================================================================== */
438 : /* Write out the image headers. */
439 : /* ==================================================================== */
440 238 : PCIDSKBuffer ih( 1024 );
441 :
442 119 : ih.Put( " ", 0, 1024 );
443 :
444 : // IHi.1 - Text describing Channel Contents
445 119 : ih.Put( "Contents Not Specified", 0, 64 );
446 :
447 : // IHi.2 - Filename storing image.
448 119 : if( STARTS_WITH(interleaving, "FILE") )
449 8 : ih.Put( "<uninitialized>", 64, 64 );
450 :
451 : // IHi.3 - Creation time and date.
452 119 : ih.Put( current_time, 128, 16 );
453 :
454 : // IHi.4 - Creation time and date.
455 119 : ih.Put( current_time, 144, 16 );
456 :
457 119 : interfaces->io->Seek( io_handle, image_header_start*512, SEEK_SET );
458 :
459 242 : for( chan_index = 0; chan_index < channel_count; chan_index++ )
460 : {
461 123 : ih.Put(DataTypeName(channel_types[chan_index]), 160, 8);
462 :
463 123 : if( STARTS_WITH(options.c_str(), "TILED") )
464 : {
465 : char sis_filename[65];
466 7 : snprintf( sis_filename, sizeof(sis_filename), "/SIS=%d", chan_index );
467 7 : ih.Put( sis_filename, 64, 64 );
468 :
469 : // IHi.6.7 - IHi.6.10
470 7 : ih.Put( 0, 250, 8 );
471 7 : ih.Put( 0, 258, 8 );
472 7 : ih.Put( pixels, 266, 8 );
473 7 : ih.Put( lines, 274, 8 );
474 :
475 : // IHi.6.11
476 7 : ih.Put( 1, 282, 8 );
477 : }
478 116 : else if( nocreate )
479 : {
480 0 : std::string oName(64, ' ');
481 :
482 0 : if( oLinkFilename.size() <= 64 )
483 : {
484 0 : std::stringstream oSS(oName);
485 0 : oSS << oLinkFilename;
486 0 : oName = oSS.str();
487 : }
488 :
489 0 : ih.Put( oName.c_str(), 64, 64 );
490 :
491 : // IHi.6.7 - IHi.6.10
492 0 : ih.Put( 0, 250, 8 );
493 0 : ih.Put( 0, 258, 8 );
494 0 : ih.Put( pixels, 266, 8 );
495 0 : ih.Put( lines, 274, 8 );
496 :
497 : // IHi.6.11
498 0 : ih.Put( chan_index+1, 282, 8 );
499 : }
500 :
501 123 : interfaces->io->Write( ih.buffer, 1024, 1, io_handle );
502 : }
503 :
504 623 : for( chan_index = channel_count;
505 623 : chan_index < image_header_count;
506 : chan_index++ )
507 : {
508 504 : ih.Put( "", 160, 8 );
509 504 : ih.Put( "<uninitialized>", 64, 64 );
510 504 : ih.Put( "", 250, 40 );
511 :
512 504 : interfaces->io->Write( ih.buffer, 1024, 1, io_handle );
513 : }
514 :
515 : /* ==================================================================== */
516 : /* Write out the segment pointers, all spaces. */
517 : /* ==================================================================== */
518 238 : PCIDSKBuffer segment_pointers( (int) (segment_ptr_size*512) );
519 119 : segment_pointers.Put( " ", 0, (int) (segment_ptr_size*512) );
520 :
521 119 : interfaces->io->Seek( io_handle, segment_ptr_start*512, SEEK_SET );
522 119 : interfaces->io->Write( segment_pointers.buffer, segment_ptr_size, 512,
523 119 : io_handle );
524 :
525 : /* -------------------------------------------------------------------- */
526 : /* Ensure we write out something at the end of the image data */
527 : /* to force the file size. */
528 : /* -------------------------------------------------------------------- */
529 119 : if( image_data_size > 0 && !nozero)
530 : {
531 : /* -------------------------------------------------------------------- */
532 : /* This prezero operation using the Win32 API is slow. Doing it */
533 : /* ourselves allow the creation to be 50% faster. */
534 : /* -------------------------------------------------------------------- */
535 69 : size_t nBufSize = 524288; // Number of 512 blocks for 256MB
536 138 : std::unique_ptr<char[]> oZeroAutoPtr(new char[nBufSize*512]);
537 69 : char* puBuf = oZeroAutoPtr.get();
538 69 : std::memset(puBuf,0,nBufSize*512); //prezero
539 :
540 69 : uint64 nBlocksRest = image_data_size;
541 69 : uint64 nOff = image_data_start;
542 138 : while(nBlocksRest > 0)
543 : {
544 69 : size_t nWriteBlocks = nBufSize;
545 69 : if(nBlocksRest < nBufSize)
546 : {
547 69 : nWriteBlocks = static_cast<size_t>(nBlocksRest);
548 69 : nBlocksRest = 0;
549 : }
550 69 : interfaces->io->Seek( io_handle, nOff*512, SEEK_SET );
551 69 : interfaces->io->Write( puBuf, nWriteBlocks, 512, io_handle );
552 :
553 69 : nOff+=nWriteBlocks;
554 69 : if(nBlocksRest != 0)
555 : {
556 0 : nBlocksRest -= nWriteBlocks;
557 : }
558 : }
559 : }
560 :
561 : /* -------------------------------------------------------------------- */
562 : /* Close the raw file, and reopen as a pcidsk file. */
563 : /* -------------------------------------------------------------------- */
564 119 : oHandleAutoPtr.Close();
565 :
566 357 : auto file = std::unique_ptr<PCIDSKFile>(Open( filename, "r+", interfaces ));
567 :
568 118 : if(oLinkFilename.size() > 64)
569 : {
570 0 : int nSegId = file->CreateSegment( "Link", "Sys_Link", SEG_SYS, 1);
571 :
572 : CLinkSegment * poSeg =
573 0 : dynamic_cast<CLinkSegment*>(file->GetSegment(nSegId));
574 :
575 0 : if(nullptr != poSeg)
576 : {
577 0 : poSeg->SetPath(oLinkFilename);
578 0 : poSeg->Synchronize();
579 : }
580 :
581 0 : for( chan_index = 0; chan_index < channel_count; chan_index++ )
582 : {
583 0 : uint64 ih_offset = (uint64)image_header_start*512 + (uint64)chan_index*1024;
584 :
585 0 : file->ReadFromFile( ih.buffer, ih_offset, 1024 );
586 :
587 0 : std::string oName(64, ' ');
588 0 : std::stringstream oSS(oName);
589 0 : oSS << "LNK=";
590 0 : oSS << std::setw(4) << nSegId;
591 0 : oSS << "File requires a newer PCIDSK file reader to read";
592 0 : oName = oSS.str();
593 :
594 0 : ih.Put( oName.c_str(), 64, 64 );
595 :
596 0 : file->WriteToFile( ih.buffer, ih_offset, 1024 );
597 : }
598 :
599 0 : file.reset();
600 0 : file.reset(Open( filename, "r+", interfaces ));
601 : }
602 :
603 : /* -------------------------------------------------------------------- */
604 : /* Create a default georeferencing segment. */
605 : /* -------------------------------------------------------------------- */
606 272 : file->CreateSegment( "GEOref",
607 : "Master Georeferencing Segment for File",
608 118 : SEG_GEO, 6 );
609 :
610 : /* -------------------------------------------------------------------- */
611 : /* If the dataset is tiled, create the file band data. */
612 : /* -------------------------------------------------------------------- */
613 109 : if( STARTS_WITH(options.c_str(), "TILED") )
614 : {
615 7 : file->SetMetadataValue( "_DBLayout", options );
616 :
617 14 : CPCIDSKBlockFile oBlockFile(file.get());
618 :
619 7 : SysTileDir * poTileDir = oBlockFile.CreateTileDir();
620 :
621 14 : for( chan_index = 0; chan_index < channel_count; chan_index++ )
622 : {
623 14 : poTileDir->CreateTileLayer(pixels, lines, tilesize, tilesize,
624 7 : channel_types[chan_index],
625 : compression);
626 : }
627 : }
628 :
629 : /* -------------------------------------------------------------------- */
630 : /* If we have a non-tiled FILE interleaved file, should we */
631 : /* create external band files now? */
632 : /* -------------------------------------------------------------------- */
633 218 : if( STARTS_WITH(interleaving, "FILE")
634 8 : && !STARTS_WITH(options.c_str(), "TILED")
635 117 : && !nocreate )
636 : {
637 2 : for( chan_index = 0; chan_index < channel_count; chan_index++ )
638 : {
639 1 : PCIDSKChannel *channel = file->GetChannel( chan_index + 1 );
640 1 : int pixel_size = DataTypeSize(channel->GetType());
641 :
642 : // build a band filename that uses the basename of the PCIDSK
643 : // file, and adds ".nnn" based on the band.
644 2 : std::string band_filename = filename;
645 : char ext[16];
646 1 : CPLsnprintf( ext, sizeof(ext), ".%03d", chan_index+1 );
647 :
648 1 : size_t last_dot = band_filename.find_last_of(".");
649 1 : if( last_dot != std::string::npos
650 2 : && (band_filename.find_last_of("/\\:") == std::string::npos
651 1 : || band_filename.find_last_of("/\\:") < last_dot) )
652 : {
653 1 : band_filename.resize( last_dot );
654 : }
655 :
656 1 : band_filename += ext;
657 :
658 : // Now build a version without a path.
659 1 : std::string relative_band_filename;
660 1 : size_t path_div = band_filename.find_last_of( "/\\:" );
661 1 : if( path_div == std::string::npos )
662 0 : relative_band_filename = band_filename;
663 : else
664 1 : relative_band_filename = band_filename.c_str() + path_div + 1;
665 :
666 : // create the file - ought we write the whole file?
667 1 : void *band_io_handle = interfaces->io->Open( band_filename, "w" );
668 1 : interfaces->io->Write( "\0", 1, 1, band_io_handle );
669 1 : interfaces->io->Close( band_io_handle );
670 :
671 : // Set the channel header information.
672 1 : channel->SetChanInfo( std::move(relative_band_filename), 0, pixel_size,
673 1 : static_cast<size_t>(pixel_size) * pixels, true );
674 : }
675 : }
676 :
677 109 : return file.release();
678 : }
|