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