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