LCOV - code coverage report
Current view: top level - frmts/pcidsk/sdk/core - pcidskcreate.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 218 290 75.2 %
Date: 2025-02-20 10:14:44 Functions: 4 4 100.0 %

          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         124 : 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         124 :     if( pixels < 0 || pixels > 99999999 ||
      58         124 :         lines < 0 || lines > 99999999 ||
      59         124 :         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         124 :     PCIDSKInterfaces default_interfaces;
      69         124 :     if( interfaces == nullptr )
      70           0 :         interfaces = &default_interfaces;
      71             : 
      72             : /* -------------------------------------------------------------------- */
      73             : /*      Default the channel types to all 8U if not provided.            */
      74             : /* -------------------------------------------------------------------- */
      75         248 :     std::vector<eChanType> default_channel_types;
      76             : 
      77         124 :     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         124 :     const char *interleaving = nullptr;
      87         248 :     std::string compression = "NONE";
      88         124 :     bool nocreate = false;
      89         124 :     int  tilesize = PCIDSK_DEFAULT_TILE_SIZE;
      90         248 :     std::string oLinkFilename;
      91             : 
      92         248 :     std::string options = oOrigOptions;
      93         124 :     UCaseStr( options );
      94         684 :     for(auto & c : options)
      95             :     {
      96         560 :         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         124 :     auto apszInterleavingOptions =
     104         124 :         {"FILE", "PIXEL", "BAND", "TILED", "NOZERO"};
     105         377 :     for(auto pszInterleavingOption : apszInterleavingOptions)
     106             :     {
     107         377 :         std::size_t nPos = options.find(pszInterleavingOption);
     108         377 :         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         377 :         else if(nPos == 0)
     126         124 :             break;
     127             :     }
     128             : 
     129         124 :     if(STARTS_WITH(options.c_str(), "PIXEL") )
     130           0 :         interleaving = "PIXEL";
     131         124 :     else if( STARTS_WITH(options.c_str(), "BAND") )
     132         116 :         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         124 :     bool nozero = options.find("NOZERO") != std::string::npos;
     156             : 
     157             : /* -------------------------------------------------------------------- */
     158             : /*      Validate the channel types.                                     */
     159             : /* -------------------------------------------------------------------- */
     160         124 :     int16 channels[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
     161             :     int chan_index;
     162         124 :     bool regular = true;
     163             : 
     164         251 :     for( chan_index=0; chan_index < channel_count; chan_index++ )
     165             :     {
     166         127 :         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         127 :         channels[((int) channel_types[chan_index])]++;
     172             :     }
     173             : 
     174         124 :     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         132 :     void *io_handle = interfaces->io->Open( filename, "w+" );
     187             : 
     188         120 :     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         120 :         IOHandleAutoPtr(const PCIDSKInterfaces * interfacesIn,
     199             :                         void * io_handleIn)
     200         120 :             : interfaces(interfacesIn),
     201         120 :               io_handle(io_handleIn)
     202             :         {
     203         120 :         }
     204         120 :         ~IOHandleAutoPtr()
     205         120 :         {
     206         120 :             Close();
     207         120 :         }
     208         240 :         void Close()
     209             :         {
     210         240 :             if (interfaces && io_handle)
     211         120 :                 interfaces->io->Close(io_handle);
     212             : 
     213         240 :             io_handle = nullptr;
     214         240 :         }
     215             :     };
     216             : 
     217         240 :     IOHandleAutoPtr oHandleAutoPtr(interfaces, io_handle);
     218             : 
     219             : /* ==================================================================== */
     220             : /*      Establish some key file layout information.                     */
     221             : /* ==================================================================== */
     222         120 :     int image_header_start = 1;                    // in blocks
     223         120 :     uint64 image_data_start, image_data_size=0;    // in blocks
     224         120 :     uint64 segment_ptr_start, segment_ptr_size=64; // in blocks
     225             :     int pixel_group_size, line_size;               // in bytes
     226         120 :     int image_header_count = channel_count;
     227             : 
     228             : /* -------------------------------------------------------------------- */
     229             : /*      Pixel interleaved.                                              */
     230             : /* -------------------------------------------------------------------- */
     231         120 :     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         120 :     else if( strcmp(interleaving,"BAND") == 0 )
     258             :     {
     259         112 :         pixel_group_size =
     260         112 :             channels[CHN_8U]  * DataTypeSize(CHN_8U) +
     261         112 :             channels[CHN_16S] * DataTypeSize(CHN_16S) +
     262         112 :             channels[CHN_16U] * DataTypeSize(CHN_16U) +
     263         112 :             channels[CHN_32S] * DataTypeSize(CHN_32S) +
     264         112 :             channels[CHN_32U] * DataTypeSize(CHN_32U) +
     265         112 :             channels[CHN_32R] * DataTypeSize(CHN_32R) +
     266         112 :             channels[CHN_64S] * DataTypeSize(CHN_64S) +
     267         112 :             channels[CHN_64U] * DataTypeSize(CHN_64U) +
     268         112 :             channels[CHN_64R] * DataTypeSize(CHN_64R) +
     269         112 :             channels[CHN_C16S] * DataTypeSize(CHN_C16S) +
     270         112 :             channels[CHN_C16U] * DataTypeSize(CHN_C16U) +
     271         112 :             channels[CHN_C32S] * DataTypeSize(CHN_C32S) +
     272         112 :             channels[CHN_C32U] * DataTypeSize(CHN_C32U) +
     273         112 :             channels[CHN_C32R] * DataTypeSize(CHN_C32R);
     274             :         // BAND interleaved bands are tightly packed.
     275         112 :         image_data_size =
     276         112 :             (((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         120 :     segment_ptr_start = image_header_start + image_header_count*2;
     299         120 :     image_data_start = segment_ptr_start + segment_ptr_size;
     300             : 
     301             : /* ==================================================================== */
     302             : /*      Prepare the file header.                                        */
     303             : /* ==================================================================== */
     304         240 :     PCIDSKBuffer fh(512);
     305             : 
     306             :     char current_time[17];
     307         120 :     GetCurrentDateTime( current_time );
     308             : 
     309             :     // Initialize everything to spaces.
     310         120 :     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         120 :     fh.Put( "PCIDSK", 0, 8 );
     318             : 
     319             :     // FH2 - TODO: Allow caller to pass this in.
     320         120 :     fh.Put( "SDK V1.0", 8, 8 );
     321             : 
     322             :     // FH3 - file size later.
     323         120 :     fh.Put( (image_data_start + image_data_size), 16, 16 );
     324             : 
     325             :     // FH4 - 16 characters reserved - spaces.
     326             : 
     327             :     // FH5 - Description
     328         120 :     fh.Put( filename.c_str(), 48, 64 );
     329             : 
     330             :     // FH6 - Facility
     331         120 :     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         120 :     fh.Put( current_time, 272, 16 );
     337             : 
     338             :     // FH9 Update date/time
     339         120 :     fh.Put( current_time, 288, 16 );
     340             : 
     341             : /* -------------------------------------------------------------------- */
     342             : /*      Image Data                                                      */
     343             : /* -------------------------------------------------------------------- */
     344             :     // FH10 - start block of image data
     345         120 :     fh.Put( image_data_start+1, 304, 16 );
     346             : 
     347             :     // FH11 - number of blocks of image data.
     348         120 :     fh.Put( image_data_size, 320, 16 );
     349             : 
     350             :     // FH12 - start block of image headers.
     351         120 :     fh.Put( image_header_start+1, 336, 16 );
     352             : 
     353             :     // FH13 - number of blocks of image headers.
     354         120 :     fh.Put( image_header_count*2, 352, 8);
     355             : 
     356             :     // FH14 - interleaving.
     357         120 :     fh.Put( interleaving, 360, 8);
     358             : 
     359             :     // FH15 - reserved - MIXED is for some ancient backwards compatibility.
     360         120 :     fh.Put( "MIXED", 368, 8);
     361             : 
     362             :     // FH16 - number of image bands.
     363         120 :     fh.Put( channel_count, 376, 8 );
     364             : 
     365             :     // FH17 - width of image in pixels.
     366         120 :     fh.Put( pixels, 384, 8 );
     367             : 
     368             :     // FH18 - height of image in pixels.
     369         120 :     fh.Put( lines, 392, 8 );
     370             : 
     371             :     // FH19 - pixel ground size interpretation.
     372         120 :     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         120 :     fh.Put( "1.0", 408, 16 );
     378         120 :     fh.Put( "1.0", 424, 16 );
     379             : 
     380             : /* -------------------------------------------------------------------- */
     381             : /*      Segment Pointers                                                */
     382             : /* -------------------------------------------------------------------- */
     383             :     // FH22 - start block of segment pointers.
     384         120 :     fh.Put( segment_ptr_start+1, 440, 16 );
     385             : 
     386             :     // fH23 - number of blocks of segment pointers.
     387         120 :     fh.Put( segment_ptr_size, 456, 8 );
     388             : 
     389             : /* -------------------------------------------------------------------- */
     390             : /*      Number of different types of Channels                           */
     391             : /* -------------------------------------------------------------------- */
     392             :     // FH24.1 - 8U bands.
     393         120 :     fh.Put( channels[CHN_8U], 464, 4 );
     394             : 
     395             :     // FH24.2 - 16S bands.
     396         120 :     fh.Put( channels[CHN_16S], 468, 4 );
     397             : 
     398             :     // FH24.3 - 16U bands.
     399         120 :     fh.Put( channels[CHN_16U], 472, 4 );
     400             : 
     401             :     // FH24.4 - 32R bands.
     402         120 :     fh.Put( channels[CHN_32R], 476, 4 );
     403             : 
     404             :     // FH24.5 - C16U bands
     405         120 :     fh.Put( channels[CHN_C16U], 480, 4 );
     406             : 
     407             :     // FH24.6 - C16S bands
     408         120 :     fh.Put( channels[CHN_C16S], 484, 4 );
     409             : 
     410             :     // FH24.7 - C32R bands
     411         120 :     fh.Put( channels[CHN_C32R], 488, 4 );
     412             : 
     413         120 :     if (!BigEndianSystem())
     414             :     {
     415         120 :         SwapData(channels + CHN_32S, 2, 1);
     416         120 :         SwapData(channels + CHN_32U, 2, 1);
     417         120 :         SwapData(channels + CHN_64S, 2, 1);
     418         120 :         SwapData(channels + CHN_64U, 2, 1);
     419         120 :         SwapData(channels + CHN_64R, 2, 1);
     420         120 :         SwapData(channels + CHN_C32S, 2, 1);
     421         120 :         SwapData(channels + CHN_C32U, 2, 1);
     422             :     }
     423             : 
     424         120 :     fh.PutBin(channels[CHN_32S], 492);
     425         120 :     fh.PutBin(channels[CHN_32U], 494);
     426         120 :     fh.PutBin(channels[CHN_64S], 496);
     427         120 :     fh.PutBin(channels[CHN_64U], 498);
     428         120 :     fh.PutBin(channels[CHN_64R], 500);
     429         120 :     fh.PutBin(channels[CHN_C32S], 502);
     430         120 :     fh.PutBin(channels[CHN_C32U], 504);
     431             : 
     432             : /* -------------------------------------------------------------------- */
     433             : /*      Write out the file header.                                      */
     434             : /* -------------------------------------------------------------------- */
     435         120 :     interfaces->io->Write( fh.buffer, 512, 1, io_handle );
     436             : 
     437             : /* ==================================================================== */
     438             : /*      Write out the image headers.                                    */
     439             : /* ==================================================================== */
     440         240 :     PCIDSKBuffer ih( 1024 );
     441             : 
     442         120 :     ih.Put( " ", 0, 1024 );
     443             : 
     444             :     // IHi.1 - Text describing Channel Contents
     445         120 :     ih.Put( "Contents Not Specified", 0, 64 );
     446             : 
     447             :     // IHi.2 - Filename storing image.
     448         120 :     if( STARTS_WITH(interleaving, "FILE") )
     449           8 :         ih.Put( "<uninitialized>", 64, 64 );
     450             : 
     451             :     // IHi.3 - Creation time and date.
     452         120 :     ih.Put( current_time, 128, 16 );
     453             : 
     454             :     // IHi.4 - Creation time and date.
     455         120 :     ih.Put( current_time, 144, 16 );
     456             : 
     457         120 :     interfaces->io->Seek( io_handle, image_header_start*512, SEEK_SET );
     458             : 
     459         244 :     for( chan_index = 0; chan_index < channel_count; chan_index++ )
     460             :     {
     461         124 :         ih.Put(DataTypeName(channel_types[chan_index]), 160, 8);
     462             : 
     463         124 :         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         117 :         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         124 :         interfaces->io->Write( ih.buffer, 1024, 1, io_handle );
     502             :     }
     503             : 
     504         624 :     for( chan_index = channel_count;
     505         624 :          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         240 :     PCIDSKBuffer segment_pointers( (int) (segment_ptr_size*512) );
     519         120 :     segment_pointers.Put( " ", 0, (int) (segment_ptr_size*512) );
     520             : 
     521         120 :     interfaces->io->Seek( io_handle, segment_ptr_start*512, SEEK_SET );
     522         120 :     interfaces->io->Write( segment_pointers.buffer, segment_ptr_size, 512,
     523         120 :                            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         120 :     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          70 :         size_t nBufSize = 524288; // Number of 512 blocks for 256MB
     536         140 :         std::unique_ptr<char[]> oZeroAutoPtr(new char[nBufSize*512]);
     537          70 :         char* puBuf = oZeroAutoPtr.get();
     538          70 :         std::memset(puBuf,0,nBufSize*512); //prezero
     539             : 
     540          70 :         uint64 nBlocksRest = image_data_size;
     541          70 :         uint64 nOff = image_data_start;
     542         140 :         while(nBlocksRest > 0)
     543             :         {
     544          70 :             size_t nWriteBlocks = nBufSize;
     545          70 :             if(nBlocksRest < nBufSize)
     546             :             {
     547          70 :                 nWriteBlocks = static_cast<size_t>(nBlocksRest);
     548          70 :                 nBlocksRest = 0;
     549             :             }
     550          70 :             interfaces->io->Seek( io_handle, nOff*512, SEEK_SET );
     551          70 :             interfaces->io->Write( puBuf, nWriteBlocks, 512, io_handle );
     552             : 
     553          70 :             nOff+=nWriteBlocks;
     554          70 :             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         120 :     oHandleAutoPtr.Close();
     565             : 
     566         360 :     auto file = std::unique_ptr<PCIDSKFile>(Open( filename, "r+", interfaces ));
     567             : 
     568         119 :     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         274 :     file->CreateSegment( "GEOref",
     607             :                          "Master Georeferencing Segment for File",
     608         119 :                          SEG_GEO, 6 );
     609             : 
     610             : /* -------------------------------------------------------------------- */
     611             : /*      If the dataset is tiled, create the file band data.             */
     612             : /* -------------------------------------------------------------------- */
     613         110 :     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         220 :     if( STARTS_WITH(interleaving, "FILE")
     634           8 :         && !STARTS_WITH(options.c_str(), "TILED")
     635         118 :         && !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         110 :     return file.release();
     678             : }

Generated by: LCOV version 1.14