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