Line data Source code
1 : /******************************************************************************
2 : * $Id$
3 : *
4 : * Project: CEOS Translator
5 : * Purpose: Implementation of non-GDAL dependent CEOS support.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
10 : * Copyright (c) 2007-2012, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "ceosopen.h"
32 :
33 4 : CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused)
34 : {
35 4 : }
36 :
37 : /************************************************************************/
38 : /* CEOSScanInt() */
39 : /* */
40 : /* Read up to nMaxChars from the passed string, and interpret */
41 : /* as an integer. */
42 : /************************************************************************/
43 :
44 18 : static int CEOSScanInt(const char *pszString, int nMaxChars)
45 :
46 : {
47 18 : char szWorking[33] = {0};
48 : int i;
49 :
50 18 : if (nMaxChars > 32 || nMaxChars == 0)
51 0 : nMaxChars = 32;
52 :
53 114 : for (i = 0; i < nMaxChars && pszString[i] != '\0'; i++)
54 96 : szWorking[i] = pszString[i];
55 :
56 18 : szWorking[i] = '\0';
57 :
58 18 : return (atoi(szWorking));
59 : }
60 :
61 : /************************************************************************/
62 : /* CEOSReadRecord() */
63 : /* */
64 : /* Read a single CEOS record at the current point in the file. */
65 : /* Return NULL after reporting an error if it fails, otherwise */
66 : /* return the record. */
67 : /************************************************************************/
68 :
69 4 : CEOSRecord *CEOSReadRecord(CEOSImage *psImage)
70 :
71 : {
72 : GByte abyHeader[12];
73 : CEOSRecord *psRecord;
74 : GUInt32 nRecordNumUInt32, nLengthUInt32;
75 :
76 : /* -------------------------------------------------------------------- */
77 : /* Read the standard CEOS header. */
78 : /* -------------------------------------------------------------------- */
79 4 : if (VSIFEofL(psImage->fpImage))
80 0 : return NULL;
81 :
82 4 : if (VSIFReadL(abyHeader, 1, 12, psImage->fpImage) != 12)
83 : {
84 0 : CPLError(CE_Failure, CPLE_FileIO,
85 : "Ran out of data reading CEOS record.");
86 0 : return NULL;
87 : }
88 :
89 : /* -------------------------------------------------------------------- */
90 : /* Extract this information. */
91 : /* -------------------------------------------------------------------- */
92 4 : psRecord = (CEOSRecord *)CPLMalloc(sizeof(CEOSRecord));
93 4 : if (psImage->bLittleEndian)
94 : {
95 2 : CPL_SWAP32PTR(abyHeader + 0);
96 2 : CPL_SWAP32PTR(abyHeader + 8);
97 : }
98 :
99 4 : nRecordNumUInt32 = ((unsigned)abyHeader[0] << 24) + (abyHeader[1] << 16) +
100 4 : (abyHeader[2] << 8) + abyHeader[3];
101 :
102 4 : psRecord->nRecordType = ((unsigned)abyHeader[4] << 24) +
103 4 : (abyHeader[5] << 16) + (abyHeader[6] << 8) +
104 4 : abyHeader[7];
105 :
106 4 : nLengthUInt32 = ((unsigned)abyHeader[8] << 24) + (abyHeader[9] << 16) +
107 4 : (abyHeader[10] << 8) + abyHeader[11];
108 :
109 : /* -------------------------------------------------------------------- */
110 : /* Does it look reasonable? We assume there can't be too many */
111 : /* records and that the length must be between 12 and 200000. */
112 : /* -------------------------------------------------------------------- */
113 4 : if (nRecordNumUInt32 > 200000 || nLengthUInt32 < 12 ||
114 : nLengthUInt32 > 200000)
115 : {
116 0 : CPLError(CE_Failure, CPLE_AppDefined,
117 : "CEOS record leader appears to be corrupt.\n"
118 : "Record Number = %u, Record Length = %u\n",
119 : nRecordNumUInt32, nLengthUInt32);
120 0 : CPLFree(psRecord);
121 0 : return NULL;
122 : }
123 :
124 4 : psRecord->nRecordNum = (int)nRecordNumUInt32;
125 4 : psRecord->nLength = (int)nLengthUInt32;
126 :
127 : /* -------------------------------------------------------------------- */
128 : /* Read the remainder of the record into a buffer. Ensure that */
129 : /* the first 12 bytes gets moved into this buffer as well. */
130 : /* -------------------------------------------------------------------- */
131 4 : psRecord->pachData = (char *)VSI_MALLOC_VERBOSE(psRecord->nLength);
132 4 : if (psRecord->pachData == NULL)
133 : {
134 0 : CPLFree(psRecord);
135 0 : return NULL;
136 : }
137 :
138 4 : memcpy(psRecord->pachData, abyHeader, 12);
139 :
140 4 : if ((int)VSIFReadL(psRecord->pachData + 12, 1, psRecord->nLength - 12,
141 4 : psImage->fpImage) != psRecord->nLength - 12)
142 : {
143 0 : CPLError(CE_Failure, CPLE_FileIO, "Short read on CEOS record data.\n");
144 0 : CPLFree(psRecord->pachData);
145 0 : CPLFree(psRecord);
146 0 : return NULL;
147 : }
148 :
149 4 : return psRecord;
150 : }
151 :
152 : /************************************************************************/
153 : /* CEOSDestroyRecord() */
154 : /* */
155 : /* Free a record. */
156 : /************************************************************************/
157 :
158 4 : void CEOSDestroyRecord(CEOSRecord *psRecord)
159 :
160 : {
161 4 : if (psRecord)
162 : {
163 4 : CPLFree(psRecord->pachData);
164 4 : CPLFree(psRecord);
165 : }
166 4 : }
167 :
168 : /************************************************************************/
169 : /* CEOSOpen() */
170 : /************************************************************************/
171 :
172 : /**
173 : * Open a CEOS transfer.
174 : *
175 : * @param pszFilename The name of the CEOS imagery file (i.e. imag_01.dat).
176 : * @param pszAccess An fopen() style access string. Should be either "rb" for
177 : * read-only access, or "r+b" for read, and update access.
178 : *
179 : * @return A CEOSImage pointer as a handle to the image. The CEOSImage also
180 : * has various information about the image available. A NULL is returned
181 : * if an error occurs.
182 : */
183 :
184 4 : CEOSImage *CEOSOpen(const char *pszFilename, const char *pszAccess)
185 :
186 : {
187 : VSILFILE *fp;
188 : CEOSRecord *psRecord;
189 : CEOSImage *psImage;
190 : int nSeqNum, i;
191 : GByte abyHeader[16];
192 :
193 : /* -------------------------------------------------------------------- */
194 : /* Try to open the imagery file. */
195 : /* -------------------------------------------------------------------- */
196 4 : fp = VSIFOpenL(pszFilename, pszAccess);
197 :
198 4 : if (fp == NULL)
199 : {
200 0 : CPLError(CE_Failure, CPLE_OpenFailed,
201 : "Failed to open CEOS file `%s' with access `%s'.\n",
202 : pszFilename, pszAccess);
203 0 : return NULL;
204 : }
205 :
206 : /* -------------------------------------------------------------------- */
207 : /* Create a CEOSImage structure, and initialize it. */
208 : /* -------------------------------------------------------------------- */
209 4 : psImage = (CEOSImage *)CPLCalloc(1, sizeof(CEOSImage));
210 4 : psImage->fpImage = fp;
211 :
212 4 : psImage->nPixels = psImage->nLines = psImage->nBands = 0;
213 :
214 : /* -------------------------------------------------------------------- */
215 : /* Preread info on the first record, to establish if it is */
216 : /* little endian. */
217 : /* -------------------------------------------------------------------- */
218 4 : if (VSIFReadL(abyHeader, 16, 1, fp) != 1 || VSIFSeekL(fp, 0, SEEK_SET) < 0)
219 : {
220 0 : CEOSClose(psImage);
221 0 : return NULL;
222 : }
223 :
224 4 : if (abyHeader[0] != 0 || abyHeader[1] != 0)
225 2 : psImage->bLittleEndian = TRUE;
226 :
227 : /* -------------------------------------------------------------------- */
228 : /* Try to read the header record. */
229 : /* -------------------------------------------------------------------- */
230 4 : psRecord = CEOSReadRecord(psImage);
231 4 : if (psRecord == NULL || psRecord->nLength < 288 + 4)
232 : {
233 0 : CEOSDestroyRecord(psRecord);
234 0 : CEOSClose(psImage);
235 0 : return NULL;
236 : }
237 :
238 4 : char format_doc[13] = {0};
239 4 : memcpy(format_doc, psRecord->pachData + 16, 12);
240 4 : if (strncmp("CEOS-SAR-CCT", format_doc, 12) == 0)
241 : {
242 2 : CEOSDestroyRecord(psRecord);
243 2 : CEOSClose(psImage);
244 2 : return NULL;
245 : }
246 :
247 2 : if (psRecord->nRecordType != CRT_IMAGE_FDR)
248 : {
249 0 : CPLError(CE_Failure, CPLE_AppDefined,
250 : "Got a %X type record, instead of the expected\n"
251 : "file descriptor record on file %s.\n",
252 : psRecord->nRecordType, pszFilename);
253 :
254 0 : CEOSDestroyRecord(psRecord);
255 0 : CEOSClose(psImage);
256 0 : return NULL;
257 : }
258 :
259 : /* -------------------------------------------------------------------- */
260 : /* The sequence number should be 2 indicating this is the */
261 : /* imagery file. */
262 : /* -------------------------------------------------------------------- */
263 2 : nSeqNum = CEOSScanInt(psRecord->pachData + 44, 4);
264 2 : if (nSeqNum != 2)
265 : {
266 0 : CPLError(CE_Warning, CPLE_AppDefined,
267 : "Got a %d file sequence number, instead of the expected\n"
268 : "2 indicating imagery on file %s.\n"
269 : "Continuing to access anyways.\n",
270 : nSeqNum, pszFilename);
271 : }
272 :
273 : /* -------------------------------------------------------------------- */
274 : /* Extract various information. */
275 : /* -------------------------------------------------------------------- */
276 2 : psImage->nImageRecCount = CEOSScanInt(psRecord->pachData + 180, 6);
277 2 : psImage->nImageRecLength = CEOSScanInt(psRecord->pachData + 186, 6);
278 2 : psImage->nBitsPerPixel = CEOSScanInt(psRecord->pachData + 216, 4);
279 2 : psImage->nBands = CEOSScanInt(psRecord->pachData + 232, 4);
280 2 : psImage->nLines = CEOSScanInt(psRecord->pachData + 236, 8);
281 2 : psImage->nPixels = CEOSScanInt(psRecord->pachData + 248, 8);
282 :
283 2 : psImage->nPrefixBytes = CEOSScanInt(psRecord->pachData + 276, 4);
284 2 : psImage->nSuffixBytes = CEOSScanInt(psRecord->pachData + 288, 4);
285 :
286 2 : if (psImage->nImageRecLength <= 0 || psImage->nPrefixBytes < 0 ||
287 2 : psImage->nBands > INT_MAX / psImage->nImageRecLength ||
288 2 : (size_t)psImage->nBands > INT_MAX / sizeof(int))
289 : {
290 0 : CEOSDestroyRecord(psRecord);
291 0 : CEOSClose(psImage);
292 0 : return NULL;
293 : }
294 :
295 : /* -------------------------------------------------------------------- */
296 : /* Try to establish the layout of the imagery data. */
297 : /* -------------------------------------------------------------------- */
298 2 : psImage->nLineOffset = psImage->nBands * psImage->nImageRecLength;
299 :
300 2 : psImage->panDataStart = (int *)VSIMalloc(sizeof(int) * psImage->nBands);
301 2 : if (psImage->panDataStart == NULL)
302 : {
303 0 : CEOSDestroyRecord(psRecord);
304 0 : CEOSClose(psImage);
305 0 : return NULL;
306 : }
307 :
308 10 : for (i = 0; i < psImage->nBands; i++)
309 : {
310 8 : psImage->panDataStart[i] = psRecord->nLength +
311 8 : i * psImage->nImageRecLength + 12 +
312 8 : psImage->nPrefixBytes;
313 : }
314 :
315 2 : CEOSDestroyRecord(psRecord);
316 :
317 2 : return psImage;
318 : }
319 :
320 : /************************************************************************/
321 : /* CEOSReadScanline() */
322 : /************************************************************************/
323 :
324 : /**
325 : * Read a scanline of image.
326 : *
327 : * @param psCEOS The CEOS dataset handle returned by CEOSOpen().
328 : * @param nBand The band number (i.e. 1, 2, 3).
329 : * @param nScanline The scanline requested, one based.
330 : * @param pData The data buffer to read into. Must be at least nPixels *
331 : * nBitesPerPixel bits long.
332 : *
333 : * @return CPLErr Returns error indicator or CE_None if the read succeeds.
334 : */
335 :
336 3 : CPLErr CEOSReadScanline(CEOSImage *psCEOS, int nBand, int nScanline,
337 : void *pData)
338 :
339 : {
340 : int nOffset, nBytes;
341 :
342 : /*
343 : * As a short cut, I currently just seek to the data, and read it
344 : * raw, rather than trying to read ceos records properly.
345 : */
346 :
347 3 : nOffset =
348 3 : psCEOS->panDataStart[nBand - 1] + (nScanline - 1) * psCEOS->nLineOffset;
349 :
350 3 : if (VSIFSeekL(psCEOS->fpImage, nOffset, SEEK_SET) != 0)
351 : {
352 0 : CPLError(CE_Failure, CPLE_FileIO,
353 : "Seek to %d for scanline %d failed.\n", nOffset, nScanline);
354 0 : return CE_Failure;
355 : }
356 :
357 : /* -------------------------------------------------------------------- */
358 : /* Read the data. */
359 : /* -------------------------------------------------------------------- */
360 3 : nBytes = psCEOS->nPixels * psCEOS->nBitsPerPixel / 8;
361 3 : if ((int)VSIFReadL(pData, 1, nBytes, psCEOS->fpImage) != nBytes)
362 : {
363 0 : CPLError(CE_Failure, CPLE_FileIO,
364 : "Read of %d bytes for scanline %d failed.\n", nBytes,
365 : nScanline);
366 0 : return CE_Failure;
367 : }
368 :
369 3 : return CE_None;
370 : }
371 :
372 : /************************************************************************/
373 : /* CEOSClose() */
374 : /************************************************************************/
375 :
376 : /**
377 : * Close a CEOS transfer. Any open files are closed, and memory deallocated.
378 : *
379 : * @param psCEOS The CEOSImage handle from CEOSOpen to be closed.
380 : */
381 :
382 4 : void CEOSClose(CEOSImage *psCEOS)
383 :
384 : {
385 4 : CPLFree(psCEOS->panDataStart);
386 4 : CPL_IGNORE_RET_VAL_INT(VSIFCloseL(psCEOS->fpImage));
387 4 : CPLFree(psCEOS);
388 4 : }
|