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: 2024-05-03 15:49:35 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             :  * 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             : }

Generated by: LCOV version 1.14