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