Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GSC Geogrid format driver. 4 : * Purpose: Implements support for reading and writing GSC Geogrid format. 5 : * Author: Frank Warmerdam <warmerdam@pobox.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com> 9 : * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com> 10 : * 11 : * SPDX-License-Identifier: MIT 12 : ****************************************************************************/ 13 : 14 : #include "cpl_string.h" 15 : #include "gdal_frmts.h" 16 : #include "rawdataset.h" 17 : 18 : #include <algorithm> 19 : 20 : /************************************************************************/ 21 : /* ==================================================================== */ 22 : /* GSCDataset */ 23 : /* ==================================================================== */ 24 : /************************************************************************/ 25 : 26 : class GSCDataset final : public RawDataset 27 : { 28 : VSILFILE *fpImage; // image data file. 29 : 30 : double adfGeoTransform[6]; 31 : 32 : CPL_DISALLOW_COPY_ASSIGN(GSCDataset) 33 : 34 : CPLErr Close() override; 35 : 36 : public: 37 : GSCDataset(); 38 : ~GSCDataset(); 39 : 40 : CPLErr GetGeoTransform(double *padfTransform) override; 41 : 42 : static GDALDataset *Open(GDALOpenInfo *); 43 : }; 44 : 45 : /************************************************************************/ 46 : /* GSCDataset() */ 47 : /************************************************************************/ 48 : 49 2 : GSCDataset::GSCDataset() : fpImage(nullptr) 50 : { 51 2 : adfGeoTransform[0] = 0.0; 52 2 : adfGeoTransform[1] = 1.0; 53 2 : adfGeoTransform[2] = 0.0; 54 2 : adfGeoTransform[3] = 0.0; 55 2 : adfGeoTransform[4] = 0.0; 56 2 : adfGeoTransform[5] = 1.0; 57 2 : } 58 : 59 : /************************************************************************/ 60 : /* ~GSCDataset() */ 61 : /************************************************************************/ 62 : 63 4 : GSCDataset::~GSCDataset() 64 : 65 : { 66 2 : GSCDataset::Close(); 67 4 : } 68 : 69 : /************************************************************************/ 70 : /* Close() */ 71 : /************************************************************************/ 72 : 73 4 : CPLErr GSCDataset::Close() 74 : { 75 4 : CPLErr eErr = CE_None; 76 4 : if (nOpenFlags != OPEN_FLAGS_CLOSED) 77 : { 78 2 : if (GSCDataset::FlushCache(true) != CE_None) 79 0 : eErr = CE_Failure; 80 : 81 2 : if (fpImage) 82 : { 83 2 : if (VSIFCloseL(fpImage) != 0) 84 : { 85 0 : CPLError(CE_Failure, CPLE_FileIO, "I/O error"); 86 0 : eErr = CE_Failure; 87 : } 88 : } 89 : 90 2 : if (GDALPamDataset::Close() != CE_None) 91 0 : eErr = CE_Failure; 92 : } 93 4 : return eErr; 94 : } 95 : 96 : /************************************************************************/ 97 : /* GetGeoTransform() */ 98 : /************************************************************************/ 99 : 100 0 : CPLErr GSCDataset::GetGeoTransform(double *padfTransform) 101 : 102 : { 103 0 : memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6); 104 : 105 0 : return CE_None; 106 : } 107 : 108 : /************************************************************************/ 109 : /* Open() */ 110 : /************************************************************************/ 111 : 112 30632 : GDALDataset *GSCDataset::Open(GDALOpenInfo *poOpenInfo) 113 : 114 : { 115 : 116 : /* -------------------------------------------------------------------- */ 117 : /* Does this plausible look like a GSC Geogrid file? */ 118 : /* -------------------------------------------------------------------- */ 119 30632 : if (poOpenInfo->nHeaderBytes < 20) 120 27319 : return nullptr; 121 : 122 3313 : if (poOpenInfo->pabyHeader[12] != 0x02 || 123 21 : poOpenInfo->pabyHeader[13] != 0x00 || 124 3 : poOpenInfo->pabyHeader[14] != 0x00 || 125 3 : poOpenInfo->pabyHeader[15] != 0x00) 126 3311 : return nullptr; 127 : 128 2 : int nRecordLen = 129 2 : CPL_LSBWORD32(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader)[0]); 130 2 : const int nPixels = 131 2 : CPL_LSBWORD32(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader)[1]); 132 2 : const int nLines = 133 2 : CPL_LSBWORD32(reinterpret_cast<GInt32 *>(poOpenInfo->pabyHeader)[2]); 134 : 135 2 : if (nPixels < 1 || nLines < 1 || nPixels > 100000 || nLines > 100000) 136 0 : return nullptr; 137 : 138 2 : if (nRecordLen != nPixels * 4) 139 0 : return nullptr; 140 : 141 : /* -------------------------------------------------------------------- */ 142 : /* Confirm the requested access is supported. */ 143 : /* -------------------------------------------------------------------- */ 144 2 : if (poOpenInfo->eAccess == GA_Update) 145 : { 146 0 : CPLError(CE_Failure, CPLE_NotSupported, 147 : "The GSC driver does not support update access to existing " 148 : "datasets."); 149 0 : return nullptr; 150 : } 151 : 152 2 : nRecordLen += 8; // For record length markers. 153 : 154 : /* -------------------------------------------------------------------- */ 155 : /* Create a corresponding GDALDataset. */ 156 : /* -------------------------------------------------------------------- */ 157 4 : auto poDS = std::make_unique<GSCDataset>(); 158 : 159 2 : poDS->nRasterXSize = nPixels; 160 2 : poDS->nRasterYSize = nLines; 161 2 : std::swap(poDS->fpImage, poOpenInfo->fpL); 162 : 163 : /* -------------------------------------------------------------------- */ 164 : /* Read the header information in the second record. */ 165 : /* -------------------------------------------------------------------- */ 166 2 : float afHeaderInfo[8] = {0.0}; 167 : 168 4 : if (VSIFSeekL(poDS->fpImage, nRecordLen + 12, SEEK_SET) != 0 || 169 2 : VSIFReadL(afHeaderInfo, sizeof(float), 8, poDS->fpImage) != 8) 170 : { 171 0 : CPLError( 172 : CE_Failure, CPLE_FileIO, 173 : "Failure reading second record of GSC file with %d record length.", 174 : nRecordLen); 175 0 : return nullptr; 176 : } 177 : 178 18 : for (int i = 0; i < 8; i++) 179 : { 180 16 : CPL_LSBPTR32(afHeaderInfo + i); 181 : } 182 : 183 2 : poDS->adfGeoTransform[0] = afHeaderInfo[2]; 184 2 : poDS->adfGeoTransform[1] = afHeaderInfo[0]; 185 2 : poDS->adfGeoTransform[2] = 0.0; 186 2 : poDS->adfGeoTransform[3] = afHeaderInfo[5]; 187 2 : poDS->adfGeoTransform[4] = 0.0; 188 2 : poDS->adfGeoTransform[5] = -afHeaderInfo[1]; 189 : 190 : /* -------------------------------------------------------------------- */ 191 : /* Create band information objects. */ 192 : /* -------------------------------------------------------------------- */ 193 : auto poBand = RawRasterBand::Create( 194 4 : poDS.get(), 1, poDS->fpImage, nRecordLen * 2 + 4, sizeof(float), 195 : nRecordLen, GDT_Float32, RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN, 196 4 : RawRasterBand::OwnFP::NO); 197 2 : if (!poBand) 198 0 : return nullptr; 199 2 : poBand->SetNoDataValue(-1.0000000150474662199e+30); 200 2 : poDS->SetBand(1, std::move(poBand)); 201 : 202 : /* -------------------------------------------------------------------- */ 203 : /* Initialize any PAM information. */ 204 : /* -------------------------------------------------------------------- */ 205 2 : poDS->SetDescription(poOpenInfo->pszFilename); 206 2 : poDS->TryLoadXML(); 207 : 208 : /* -------------------------------------------------------------------- */ 209 : /* Check for overviews. */ 210 : /* -------------------------------------------------------------------- */ 211 2 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename); 212 : 213 2 : return poDS.release(); 214 : } 215 : 216 : /************************************************************************/ 217 : /* GDALRegister_GSC() */ 218 : /************************************************************************/ 219 : 220 1595 : void GDALRegister_GSC() 221 : 222 : { 223 1595 : if (GDALGetDriverByName("GSC") != nullptr) 224 302 : return; 225 : 226 1293 : GDALDriver *poDriver = new GDALDriver(); 227 : 228 1293 : poDriver->SetDescription("GSC"); 229 1293 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 230 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GSC Geogrid"); 231 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gsc.html"); 232 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 233 : 234 1293 : poDriver->pfnOpen = GSCDataset::Open; 235 : 236 1293 : GetGDALDriverManager()->RegisterDriver(poDriver); 237 : }