Line data Source code
1 : /* TerraSAR-X COSAR Format Driver
2 : * (C)2007 Philippe P. Vachon <philippe@cowpig.ca>
3 : * ---------------------------------------------------------------------------
4 : * Permission is hereby granted, free of charge, to any person obtaining a
5 : * copy of this software and associated documentation files (the "Software"),
6 : * to deal in the Software without restriction, including without limitation
7 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 : * and/or sell copies of the Software, and to permit persons to whom the
9 : * Software is furnished to do so, subject to the following conditions:
10 : *
11 : * The above copyright notice and this permission notice shall be included
12 : * in all copies or substantial portions of the Software.
13 : *
14 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 : * DEALINGS IN THE SOFTWARE.
21 : */
22 :
23 : #include "cpl_conv.h"
24 : #include "cpl_port.h"
25 : #include "cpl_float.h"
26 : #include "cpl_string.h"
27 : #include "cpl_vsi.h"
28 : #include "gdal_frmts.h"
29 : #include "gdal_priv.h"
30 :
31 : #include <algorithm>
32 : #include <string.h>
33 :
34 : /* Various offsets, in bytes */
35 : // Commented out the unused defines.
36 : // #define BIB_OFFSET 0 /* Bytes in burst, valid only for ScanSAR */
37 : // #define RSRI_OFFSET 4 /* Range Sample Relative Index */
38 : constexpr int RS_OFFSET = 8; /* Range Samples, the length of a range line */
39 : // #define AS_OFFSET 12 /* Azimuth Samples, the length of an azimuth column
40 : // */ #define BI_OFFSET 16 /* Burst Index, the index number of the burst */
41 : constexpr int RTNB_OFFSET =
42 : 20; /* Rangeline total number of bytes, incl. annot. */
43 : // #define TNL_OFFSET 24 /* Total Number of Lines */
44 : constexpr int MAGIC1_OFFSET = 28; /* Magic number 1: 0x43534152 */
45 : constexpr int VERSION_NUMBER_OFFSET = 32; /* 1 for COSAR, 2 for COSSC */
46 :
47 : // #define FILLER_MAGIC 0x7F7F7F7F /* Filler value, we'll use this for a test
48 : // */
49 :
50 : class COSARDataset final : public GDALDataset
51 : {
52 : friend class COSARRasterBand;
53 : VSILFILE *m_fp = nullptr;
54 : uint32_t m_nVersion = 0;
55 :
56 : public:
57 0 : COSARDataset() = default;
58 : ~COSARDataset();
59 :
60 : static GDALDataset *Open(GDALOpenInfo *);
61 : };
62 :
63 : class COSARRasterBand final : public GDALRasterBand
64 : {
65 : uint32_t nRTNB;
66 :
67 : public:
68 : COSARRasterBand(COSARDataset *, uint32_t nRTNB);
69 : CPLErr IReadBlock(int, int, void *) override;
70 : };
71 :
72 : /*****************************************************************************
73 : * COSARRasterBand Implementation
74 : *****************************************************************************/
75 :
76 0 : COSARRasterBand::COSARRasterBand(COSARDataset *pDS, uint32_t nRTNBIn)
77 0 : : nRTNB(nRTNBIn)
78 : {
79 0 : COSARDataset *pCDS = cpl::down_cast<COSARDataset *>(pDS);
80 0 : nBlockXSize = pDS->GetRasterXSize();
81 0 : nBlockYSize = 1;
82 0 : eDataType = pCDS->m_nVersion == 1 ? GDT_CInt16 : GDT_CFloat32;
83 0 : }
84 :
85 0 : CPLErr COSARRasterBand::IReadBlock(int /*nBlockXOff*/, int nBlockYOff,
86 : void *pImage)
87 : {
88 :
89 0 : COSARDataset *pCDS = cpl::down_cast<COSARDataset *>(poDS);
90 0 : constexpr uint32_t ITEM_SIZE = 2 * sizeof(int16_t);
91 :
92 : /* Find the line we want to be at */
93 : /* To explain some magic numbers:
94 : * 4 bytes for an entire sample (2 I, 2 Q)
95 : * nBlockYOff + 4 = Y offset + 4 annotation lines at beginning
96 : * of file
97 : */
98 :
99 0 : VSIFSeekL(pCDS->m_fp,
100 0 : static_cast<vsi_l_offset>(nRTNB) * (nBlockYOff + ITEM_SIZE),
101 : SEEK_SET);
102 :
103 : /* Read RSFV and RSLV (TX-GS-DD-3307) */
104 0 : uint32_t nRSFV = 0; // Range Sample First Valid (starting at 1)
105 0 : uint32_t nRSLV = 0; // Range Sample Last Valid (starting at 1)
106 0 : VSIFReadL(&nRSFV, 1, sizeof(nRSFV), pCDS->m_fp);
107 0 : VSIFReadL(&nRSLV, 1, sizeof(nRSLV), pCDS->m_fp);
108 :
109 0 : nRSFV = CPL_MSBWORD32(nRSFV);
110 0 : nRSLV = CPL_MSBWORD32(nRSLV);
111 :
112 0 : if (nRSLV < nRSFV || nRSFV == 0 || nRSLV == 0 ||
113 0 : nRSFV - 1 >= static_cast<uint32_t>(nBlockXSize) ||
114 0 : nRSLV - 1 >= static_cast<uint32_t>(nBlockXSize) ||
115 0 : nRSFV >= this->nRTNB || nRSLV > this->nRTNB)
116 : {
117 : /* throw an error */
118 0 : CPLError(CE_Failure, CPLE_AppDefined,
119 : "RSLV/RSFV values are not sane... oh dear.\n");
120 0 : return CE_Failure;
121 : }
122 :
123 : /* zero out the range line */
124 0 : memset(pImage, 0,
125 0 : static_cast<size_t>(nBlockXSize) *
126 0 : GDALGetDataTypeSizeBytes(eDataType));
127 :
128 : /* properly account for validity mask */
129 0 : if (nRSFV > 1)
130 : {
131 0 : VSIFSeekL(pCDS->m_fp,
132 0 : static_cast<vsi_l_offset>(nRTNB) * (nBlockYOff + ITEM_SIZE) +
133 0 : (nRSFV + 1) * ITEM_SIZE,
134 : SEEK_SET);
135 : }
136 :
137 : /* Read the valid samples: */
138 0 : VSIFReadL(((char *)pImage) + (static_cast<size_t>(nRSFV - 1) * ITEM_SIZE),
139 0 : 1, static_cast<size_t>(nRSLV - nRSFV + 1) * ITEM_SIZE,
140 : pCDS->m_fp);
141 :
142 : #ifdef CPL_LSB
143 0 : GDALSwapWords(pImage, sizeof(int16_t), nBlockXSize * 2, sizeof(int16_t));
144 : #endif
145 :
146 0 : if (pCDS->m_nVersion == 2)
147 : {
148 : // Convert from half-float to float32
149 : // Iterate starting the end to avoid overwriting first values
150 0 : for (int i = nBlockXSize * 2 - 1; i >= 0; --i)
151 : {
152 0 : static_cast<GUInt32 *>(pImage)[i] =
153 0 : CPLHalfToFloat(static_cast<GUInt16 *>(pImage)[i]);
154 : }
155 : }
156 :
157 0 : return CE_None;
158 : }
159 :
160 : /*****************************************************************************
161 : * COSARDataset Implementation
162 : *****************************************************************************/
163 :
164 0 : COSARDataset::~COSARDataset()
165 : {
166 0 : if (m_fp != nullptr)
167 : {
168 0 : VSIFCloseL(m_fp);
169 : }
170 0 : }
171 :
172 30252 : GDALDataset *COSARDataset::Open(GDALOpenInfo *pOpenInfo)
173 : {
174 :
175 : /* Check if we're actually a COSAR data set. */
176 30252 : if (pOpenInfo->nHeaderBytes < VERSION_NUMBER_OFFSET + 4 ||
177 3804 : pOpenInfo->fpL == nullptr)
178 26488 : return nullptr;
179 :
180 3764 : if (!STARTS_WITH_CI((char *)pOpenInfo->pabyHeader + MAGIC1_OFFSET, "CSAR"))
181 3764 : return nullptr;
182 :
183 : uint32_t nVersionMSB;
184 0 : memcpy(&nVersionMSB, pOpenInfo->pabyHeader + VERSION_NUMBER_OFFSET,
185 : sizeof(uint32_t));
186 0 : const uint32_t nVersion = CPL_MSBWORD32(nVersionMSB);
187 0 : if (nVersion != 1 && nVersion != 2)
188 0 : return nullptr;
189 :
190 : /* -------------------------------------------------------------------- */
191 : /* Confirm the requested access is supported. */
192 : /* -------------------------------------------------------------------- */
193 0 : if (pOpenInfo->eAccess == GA_Update)
194 : {
195 0 : CPLError(CE_Failure, CPLE_NotSupported,
196 : "The COSAR driver does not support update access to existing"
197 : " datasets.\n");
198 0 : return nullptr;
199 : }
200 :
201 : /* this is a cosar dataset */
202 0 : COSARDataset *pDS = new COSARDataset();
203 0 : pDS->m_nVersion = nVersion;
204 :
205 : /* steal fp */
206 0 : std::swap(pDS->m_fp, pOpenInfo->fpL);
207 :
208 0 : VSIFSeekL(pDS->m_fp, RS_OFFSET, SEEK_SET);
209 : int32_t nXSize;
210 0 : VSIFReadL(&nXSize, 1, sizeof(nXSize), pDS->m_fp);
211 0 : pDS->nRasterXSize = CPL_MSBWORD32(nXSize);
212 :
213 : int32_t nYSize;
214 0 : VSIFReadL(&nYSize, 1, sizeof(nYSize), pDS->m_fp);
215 0 : pDS->nRasterYSize = CPL_MSBWORD32(nYSize);
216 :
217 0 : if (!GDALCheckDatasetDimensions(pDS->nRasterXSize, pDS->nRasterYSize))
218 : {
219 0 : delete pDS;
220 0 : return nullptr;
221 : }
222 :
223 0 : VSIFSeekL(pDS->m_fp, RTNB_OFFSET, SEEK_SET);
224 : uint32_t nRTNB;
225 0 : VSIFReadL(&nRTNB, 1, sizeof(nRTNB), pDS->m_fp);
226 0 : nRTNB = CPL_MSBWORD32(nRTNB);
227 :
228 : /* Add raster band */
229 0 : pDS->SetBand(1, new COSARRasterBand(pDS, nRTNB));
230 0 : return pDS;
231 : }
232 :
233 : /* register the driver with GDAL */
234 1512 : void GDALRegister_COSAR()
235 :
236 : {
237 1512 : if (GDALGetDriverByName("cosar") != nullptr)
238 295 : return;
239 :
240 1217 : GDALDriver *poDriver = new GDALDriver();
241 1217 : poDriver->SetDescription("COSAR");
242 1217 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
243 1217 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
244 1217 : "COSAR Annotated Binary Matrix (TerraSAR-X)");
245 1217 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/cosar.html");
246 1217 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
247 1217 : poDriver->pfnOpen = COSARDataset::Open;
248 1217 : GetGDALDriverManager()->RegisterDriver(poDriver);
249 : }
|