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

Generated by: LCOV version 1.14