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 31102 : GDALDataset *GSCDataset::Open(GDALOpenInfo *poOpenInfo) 113 : 114 : { 115 : 116 : /* -------------------------------------------------------------------- */ 117 : /* Does this plausible look like a GSC Geogrid file? */ 118 : /* -------------------------------------------------------------------- */ 119 31102 : if (poOpenInfo->nHeaderBytes < 20) 120 27731 : return nullptr; 121 : 122 3371 : if (poOpenInfo->pabyHeader[12] != 0x02 || 123 20 : poOpenInfo->pabyHeader[13] != 0x00 || 124 2 : poOpenInfo->pabyHeader[14] != 0x00 || 125 2 : poOpenInfo->pabyHeader[15] != 0x00) 126 3369 : 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 : ReportUpdateNotSupportedByDriver("GSC"); 147 0 : return nullptr; 148 : } 149 : 150 2 : nRecordLen += 8; // For record length markers. 151 : 152 : /* -------------------------------------------------------------------- */ 153 : /* Create a corresponding GDALDataset. */ 154 : /* -------------------------------------------------------------------- */ 155 4 : auto poDS = std::make_unique<GSCDataset>(); 156 : 157 2 : poDS->nRasterXSize = nPixels; 158 2 : poDS->nRasterYSize = nLines; 159 2 : std::swap(poDS->fpImage, poOpenInfo->fpL); 160 : 161 : /* -------------------------------------------------------------------- */ 162 : /* Read the header information in the second record. */ 163 : /* -------------------------------------------------------------------- */ 164 2 : float afHeaderInfo[8] = {0.0}; 165 : 166 4 : if (VSIFSeekL(poDS->fpImage, nRecordLen + 12, SEEK_SET) != 0 || 167 2 : VSIFReadL(afHeaderInfo, sizeof(float), 8, poDS->fpImage) != 8) 168 : { 169 0 : CPLError( 170 : CE_Failure, CPLE_FileIO, 171 : "Failure reading second record of GSC file with %d record length.", 172 : nRecordLen); 173 0 : return nullptr; 174 : } 175 : 176 18 : for (int i = 0; i < 8; i++) 177 : { 178 16 : CPL_LSBPTR32(afHeaderInfo + i); 179 : } 180 : 181 2 : poDS->adfGeoTransform[0] = afHeaderInfo[2]; 182 2 : poDS->adfGeoTransform[1] = afHeaderInfo[0]; 183 2 : poDS->adfGeoTransform[2] = 0.0; 184 2 : poDS->adfGeoTransform[3] = afHeaderInfo[5]; 185 2 : poDS->adfGeoTransform[4] = 0.0; 186 2 : poDS->adfGeoTransform[5] = -afHeaderInfo[1]; 187 : 188 : /* -------------------------------------------------------------------- */ 189 : /* Create band information objects. */ 190 : /* -------------------------------------------------------------------- */ 191 : auto poBand = RawRasterBand::Create( 192 4 : poDS.get(), 1, poDS->fpImage, nRecordLen * 2 + 4, sizeof(float), 193 : nRecordLen, GDT_Float32, RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN, 194 4 : RawRasterBand::OwnFP::NO); 195 2 : if (!poBand) 196 0 : return nullptr; 197 2 : poBand->SetNoDataValue(-1.0000000150474662199e+30); 198 2 : poDS->SetBand(1, std::move(poBand)); 199 : 200 : /* -------------------------------------------------------------------- */ 201 : /* Initialize any PAM information. */ 202 : /* -------------------------------------------------------------------- */ 203 2 : poDS->SetDescription(poOpenInfo->pszFilename); 204 2 : poDS->TryLoadXML(); 205 : 206 : /* -------------------------------------------------------------------- */ 207 : /* Check for overviews. */ 208 : /* -------------------------------------------------------------------- */ 209 2 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename); 210 : 211 2 : return poDS.release(); 212 : } 213 : 214 : /************************************************************************/ 215 : /* GDALRegister_GSC() */ 216 : /************************************************************************/ 217 : 218 1686 : void GDALRegister_GSC() 219 : 220 : { 221 1686 : if (GDALGetDriverByName("GSC") != nullptr) 222 302 : return; 223 : 224 1384 : GDALDriver *poDriver = new GDALDriver(); 225 : 226 1384 : poDriver->SetDescription("GSC"); 227 1384 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 228 1384 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GSC Geogrid"); 229 1384 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gsc.html"); 230 1384 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); 231 : 232 1384 : poDriver->pfnOpen = GSCDataset::Open; 233 : 234 1384 : GetGDALDriverManager()->RegisterDriver(poDriver); 235 : }