1 : /******************************************************************************
2 : * $Id: pauxdataset.cpp 21225 2010-12-09 19:49:33Z warmerdam $
3 : *
4 : * Project: PCI .aux Driver
5 : * Purpose: Implementation of PAuxDataset
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1999, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "rawdataset.h"
31 : #include "cpl_string.h"
32 : #include "ogr_spatialref.h"
33 :
34 : CPL_CVSID("$Id: pauxdataset.cpp 21225 2010-12-09 19:49:33Z warmerdam $");
35 :
36 : CPL_C_START
37 : void GDALRegister_PAux(void);
38 : CPL_C_END
39 :
40 : /************************************************************************/
41 : /* ==================================================================== */
42 : /* PAuxDataset */
43 : /* ==================================================================== */
44 : /************************************************************************/
45 :
46 : class PAuxRasterBand;
47 :
48 : class PAuxDataset : public RawDataset
49 : {
50 : friend class PAuxRasterBand;
51 :
52 : VSILFILE *fpImage; // image data file.
53 :
54 : int nGCPCount;
55 : GDAL_GCP *pasGCPList;
56 : char *pszGCPProjection;
57 :
58 : void ScanForGCPs();
59 : char *PCI2WKT( const char *pszGeosys, const char *pszProjParms );
60 :
61 : char *pszProjection;
62 :
63 : public:
64 : PAuxDataset();
65 : ~PAuxDataset();
66 :
67 : char *pszAuxFilename;
68 : char **papszAuxLines;
69 : int bAuxUpdated;
70 :
71 : virtual const char *GetProjectionRef();
72 : virtual CPLErr GetGeoTransform( double * );
73 : virtual CPLErr SetGeoTransform( double * );
74 :
75 : virtual int GetGCPCount();
76 : virtual const char *GetGCPProjection();
77 : virtual const GDAL_GCP *GetGCPs();
78 :
79 : static GDALDataset *Open( GDALOpenInfo * );
80 : static GDALDataset *Create( const char * pszFilename,
81 : int nXSize, int nYSize, int nBands,
82 : GDALDataType eType, char ** papszParmList );
83 : };
84 :
85 : /************************************************************************/
86 : /* ==================================================================== */
87 : /* PAuxRasterBand */
88 : /* ==================================================================== */
89 : /************************************************************************/
90 :
91 : class PAuxRasterBand : public RawRasterBand
92 : {
93 : GDALColorTable *poCT;
94 :
95 : public:
96 :
97 : PAuxRasterBand( GDALDataset *poDS, int nBand, VSILFILE * fpRaw,
98 : vsi_l_offset nImgOffset, int nPixelOffset,
99 : int nLineOffset,
100 : GDALDataType eDataType, int bNativeOrder );
101 :
102 : ~PAuxRasterBand();
103 :
104 : virtual double GetNoDataValue( int *pbSuccess = NULL );
105 : virtual CPLErr SetNoDataValue( double );
106 :
107 : virtual GDALColorTable *GetColorTable();
108 : virtual GDALColorInterp GetColorInterpretation();
109 :
110 : virtual void SetDescription( const char *pszNewDescription );
111 : };
112 :
113 : /************************************************************************/
114 : /* PAuxRasterBand() */
115 : /************************************************************************/
116 :
117 164 : PAuxRasterBand::PAuxRasterBand( GDALDataset *poDS, int nBand,
118 : VSILFILE * fpRaw, vsi_l_offset nImgOffset,
119 : int nPixelOffset, int nLineOffset,
120 : GDALDataType eDataType, int bNativeOrder )
121 : : RawRasterBand( poDS, nBand, fpRaw,
122 : nImgOffset, nPixelOffset, nLineOffset,
123 164 : eDataType, bNativeOrder, TRUE )
124 :
125 : {
126 164 : PAuxDataset *poPDS = (PAuxDataset *) poDS;
127 :
128 164 : poCT = NULL;
129 :
130 : /* -------------------------------------------------------------------- */
131 : /* Does this channel have a description? */
132 : /* -------------------------------------------------------------------- */
133 : char szTarget[128];
134 :
135 164 : sprintf( szTarget, "ChanDesc-%d", nBand );
136 164 : if( CSLFetchNameValue( poPDS->papszAuxLines, szTarget ) != NULL )
137 : GDALRasterBand::SetDescription(
138 0 : CSLFetchNameValue( poPDS->papszAuxLines, szTarget ) );
139 :
140 : /* -------------------------------------------------------------------- */
141 : /* See if we have colors. Currently we must have color zero, */
142 : /* but this shouldn't really be a limitation. */
143 : /* -------------------------------------------------------------------- */
144 164 : sprintf( szTarget, "METADATA_IMG_%d_Class_%d_Color", nBand, 0 );
145 164 : if( CSLFetchNameValue( poPDS->papszAuxLines, szTarget ) != NULL )
146 : {
147 : const char *pszLine;
148 : int i;
149 :
150 0 : poCT = new GDALColorTable();
151 :
152 0 : for( i = 0; i < 256; i++ )
153 : {
154 : int nRed, nGreen, nBlue;
155 :
156 0 : sprintf( szTarget, "METADATA_IMG_%d_Class_%d_Color", nBand, i );
157 0 : pszLine = CSLFetchNameValue( poPDS->papszAuxLines, szTarget );
158 0 : while( pszLine && *pszLine == ' ' )
159 0 : pszLine++;
160 :
161 0 : if( pszLine != NULL
162 : && EQUALN(pszLine, "(RGB:",5)
163 : && sscanf( pszLine+5, "%d %d %d",
164 : &nRed, &nGreen, &nBlue ) == 3 )
165 : {
166 : GDALColorEntry oColor;
167 :
168 0 : oColor.c1 = (short) nRed;
169 0 : oColor.c2 = (short) nGreen;
170 0 : oColor.c3 = (short) nBlue;
171 0 : oColor.c4 = 255;
172 :
173 0 : poCT->SetColorEntry( i, &oColor );
174 : }
175 : }
176 : }
177 164 : }
178 :
179 : /************************************************************************/
180 : /* ~PAuxRasterBand() */
181 : /************************************************************************/
182 :
183 164 : PAuxRasterBand::~PAuxRasterBand()
184 :
185 : {
186 164 : if( poCT != NULL )
187 0 : delete poCT;
188 164 : }
189 :
190 : /************************************************************************/
191 : /* GetNoDataValue() */
192 : /************************************************************************/
193 :
194 8 : double PAuxRasterBand::GetNoDataValue( int *pbSuccess )
195 :
196 : {
197 8 : PAuxDataset *poPDS = (PAuxDataset *) poDS;
198 : char szTarget[128];
199 : const char *pszLine;
200 :
201 8 : sprintf( szTarget, "METADATA_IMG_%d_NO_DATA_VALUE", nBand );
202 :
203 8 : pszLine = CSLFetchNameValue( poPDS->papszAuxLines, szTarget );
204 :
205 8 : if( pbSuccess != NULL )
206 8 : *pbSuccess = (pszLine != NULL);
207 :
208 8 : if( pszLine == NULL )
209 8 : return -1e8;
210 : else
211 0 : return atof(pszLine);
212 : }
213 :
214 : /************************************************************************/
215 : /* SetNoDataValue() */
216 : /************************************************************************/
217 :
218 0 : CPLErr PAuxRasterBand::SetNoDataValue( double dfNewValue )
219 :
220 : {
221 0 : PAuxDataset *poPDS = (PAuxDataset *) poDS;
222 : char szTarget[128];
223 : char szValue[128];
224 :
225 0 : if( GetAccess() == GA_ReadOnly )
226 : {
227 : CPLError( CE_Failure, CPLE_NoWriteAccess,
228 0 : "Can't update readonly dataset." );
229 0 : return CE_Failure;
230 : }
231 :
232 0 : sprintf( szTarget, "METADATA_IMG_%d_NO_DATA_VALUE", nBand );
233 0 : sprintf( szValue, "%24.12f", dfNewValue );
234 : poPDS->papszAuxLines =
235 0 : CSLSetNameValue( poPDS->papszAuxLines, szTarget, szValue );
236 :
237 0 : poPDS->bAuxUpdated = TRUE;
238 :
239 0 : return CE_None;
240 : }
241 :
242 : /************************************************************************/
243 : /* SetDescription() */
244 : /* */
245 : /* We override the set description so we can mark the auxfile */
246 : /* info as changed. */
247 : /************************************************************************/
248 :
249 0 : void PAuxRasterBand::SetDescription( const char *pszNewDescription )
250 :
251 : {
252 0 : PAuxDataset *poPDS = (PAuxDataset *) poDS;
253 :
254 0 : if( GetAccess() == GA_Update )
255 : {
256 : char szTarget[128];
257 :
258 0 : sprintf( szTarget, "ChanDesc-%d", nBand );
259 : poPDS->papszAuxLines =
260 : CSLSetNameValue( poPDS->papszAuxLines,
261 0 : szTarget, pszNewDescription );
262 :
263 0 : poPDS->bAuxUpdated = TRUE;
264 : }
265 :
266 0 : GDALRasterBand::SetDescription( pszNewDescription );
267 0 : }
268 :
269 :
270 : /************************************************************************/
271 : /* GetColorTable() */
272 : /************************************************************************/
273 :
274 0 : GDALColorTable *PAuxRasterBand::GetColorTable()
275 :
276 : {
277 0 : return poCT;
278 : }
279 :
280 : /************************************************************************/
281 : /* GetColorInterpretation() */
282 : /************************************************************************/
283 :
284 30 : GDALColorInterp PAuxRasterBand::GetColorInterpretation()
285 :
286 : {
287 30 : if( poCT == NULL )
288 30 : return GCI_Undefined;
289 : else
290 0 : return GCI_PaletteIndex;
291 : }
292 :
293 : /************************************************************************/
294 : /* ==================================================================== */
295 : /* PAuxDataset */
296 : /* ==================================================================== */
297 : /************************************************************************/
298 :
299 : /************************************************************************/
300 : /* PAuxDataset() */
301 : /************************************************************************/
302 :
303 78 : PAuxDataset::PAuxDataset()
304 : {
305 78 : papszAuxLines = NULL;
306 78 : fpImage = NULL;
307 78 : bAuxUpdated = FALSE;
308 78 : pszAuxFilename = NULL;
309 78 : nGCPCount = 0;
310 78 : pasGCPList = NULL;
311 :
312 78 : pszProjection = NULL;
313 78 : pszGCPProjection = NULL;
314 78 : }
315 :
316 : /************************************************************************/
317 : /* ~PAuxDataset() */
318 : /************************************************************************/
319 :
320 78 : PAuxDataset::~PAuxDataset()
321 :
322 : {
323 78 : FlushCache();
324 78 : if( fpImage != NULL )
325 74 : VSIFCloseL( fpImage );
326 :
327 78 : if( bAuxUpdated )
328 : {
329 42 : CSLSetNameValueSeparator( papszAuxLines, ": " );
330 42 : CSLSave( papszAuxLines, pszAuxFilename );
331 : }
332 :
333 78 : CPLFree( pszProjection );
334 :
335 78 : CPLFree( pszGCPProjection );
336 78 : GDALDeinitGCPs( nGCPCount, pasGCPList );
337 78 : CPLFree( pasGCPList );
338 :
339 78 : CPLFree( pszAuxFilename );
340 78 : CSLDestroy( papszAuxLines );
341 78 : }
342 :
343 : /************************************************************************/
344 : /* PCI2WKT() */
345 : /* */
346 : /* Convert PCI coordinate system to WKT. For now this is very */
347 : /* incomplete, but can be filled out in the future. */
348 : /************************************************************************/
349 :
350 0 : char *PAuxDataset::PCI2WKT( const char *pszGeosys,
351 : const char *pszProjParms )
352 :
353 : {
354 0 : OGRSpatialReference oSRS;
355 :
356 0 : while( *pszGeosys == ' ' )
357 0 : pszGeosys++;
358 :
359 : /* -------------------------------------------------------------------- */
360 : /* Parse projection parameters array. */
361 : /* -------------------------------------------------------------------- */
362 : double adfProjParms[16];
363 :
364 0 : memset( adfProjParms, 0, sizeof(adfProjParms) );
365 :
366 0 : if( pszProjParms != NULL )
367 : {
368 : char **papszTokens;
369 : int i;
370 :
371 0 : papszTokens = CSLTokenizeString( pszProjParms );
372 :
373 0 : for( i=0; papszTokens != NULL && papszTokens[i] != NULL && i < 16; i++)
374 0 : adfProjParms[i] = atof(papszTokens[i]);
375 :
376 0 : CSLDestroy( papszTokens );
377 : }
378 :
379 : /* -------------------------------------------------------------------- */
380 : /* Convert to SRS. */
381 : /* -------------------------------------------------------------------- */
382 0 : if( oSRS.importFromPCI( pszGeosys, NULL, adfProjParms ) == OGRERR_NONE )
383 : {
384 0 : char *pszResult = NULL;
385 :
386 0 : oSRS.exportToWkt( &pszResult );
387 :
388 0 : return pszResult;
389 : }
390 : else
391 0 : return NULL;
392 : }
393 :
394 : /************************************************************************/
395 : /* ScanForGCPs() */
396 : /************************************************************************/
397 :
398 74 : void PAuxDataset::ScanForGCPs()
399 :
400 : {
401 : #define MAX_GCP 256
402 :
403 74 : nGCPCount = 0;
404 74 : pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),MAX_GCP);
405 :
406 : /* -------------------------------------------------------------------- */
407 : /* Get the GCP coordinate system. */
408 : /* -------------------------------------------------------------------- */
409 : const char *pszMapUnits, *pszProjParms;
410 :
411 74 : pszMapUnits = CSLFetchNameValue( papszAuxLines, "GCP_1_MapUnits" );
412 74 : pszProjParms = CSLFetchNameValue( papszAuxLines, "GCP_1_ProjParms" );
413 :
414 74 : if( pszMapUnits != NULL )
415 0 : pszGCPProjection = PCI2WKT( pszMapUnits, pszProjParms );
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Collect standalone GCPs. They look like: */
419 : /* */
420 : /* GCP_1_n = row, col, x, y [,z [,"id"[, "desc"]]] */
421 : /* -------------------------------------------------------------------- */
422 : int i;
423 :
424 74 : for( i = 0; nGCPCount < MAX_GCP; i++ )
425 : {
426 : char szName[50];
427 : char **papszTokens;
428 :
429 74 : sprintf( szName, "GCP_1_%d", i+1 );
430 74 : if( CSLFetchNameValue( papszAuxLines, szName ) == NULL )
431 74 : break;
432 :
433 : papszTokens = CSLTokenizeStringComplex(
434 : CSLFetchNameValue( papszAuxLines, szName ),
435 0 : " ", TRUE, FALSE );
436 :
437 0 : if( CSLCount(papszTokens) >= 4 )
438 : {
439 0 : GDALInitGCPs( 1, pasGCPList + nGCPCount );
440 :
441 0 : pasGCPList[nGCPCount].dfGCPX = atof(papszTokens[2]);
442 0 : pasGCPList[nGCPCount].dfGCPY = atof(papszTokens[3]);
443 0 : pasGCPList[nGCPCount].dfGCPPixel = atof(papszTokens[0]);
444 0 : pasGCPList[nGCPCount].dfGCPLine = atof(papszTokens[1]);
445 :
446 0 : if( CSLCount(papszTokens) > 4 )
447 0 : pasGCPList[nGCPCount].dfGCPZ = atof(papszTokens[4]);
448 :
449 0 : CPLFree( pasGCPList[nGCPCount].pszId );
450 0 : if( CSLCount(papszTokens) > 5 )
451 : {
452 0 : pasGCPList[nGCPCount].pszId = CPLStrdup(papszTokens[5]);
453 : }
454 : else
455 : {
456 0 : sprintf( szName, "GCP_%d", i+1 );
457 0 : pasGCPList[nGCPCount].pszId = CPLStrdup( szName );
458 : }
459 :
460 0 : if( CSLCount(papszTokens) > 6 )
461 : {
462 0 : CPLFree( pasGCPList[nGCPCount].pszInfo );
463 0 : pasGCPList[nGCPCount].pszInfo = CPLStrdup(papszTokens[6]);
464 : }
465 :
466 0 : nGCPCount++;
467 : }
468 :
469 0 : CSLDestroy(papszTokens);
470 : }
471 74 : }
472 :
473 : /************************************************************************/
474 : /* GetGCPCount() */
475 : /************************************************************************/
476 :
477 0 : int PAuxDataset::GetGCPCount()
478 :
479 : {
480 0 : return nGCPCount;
481 : }
482 :
483 : /************************************************************************/
484 : /* GetGCPProjection() */
485 : /************************************************************************/
486 :
487 0 : const char *PAuxDataset::GetGCPProjection()
488 :
489 : {
490 0 : if( nGCPCount > 0 && pszGCPProjection != NULL )
491 0 : return pszGCPProjection;
492 : else
493 0 : return "";
494 : }
495 :
496 : /************************************************************************/
497 : /* GetGCP() */
498 : /************************************************************************/
499 :
500 0 : const GDAL_GCP *PAuxDataset::GetGCPs()
501 :
502 : {
503 0 : return pasGCPList;
504 : }
505 :
506 : /************************************************************************/
507 : /* GetProjectionRef() */
508 : /************************************************************************/
509 :
510 0 : const char *PAuxDataset::GetProjectionRef()
511 :
512 : {
513 0 : if( pszProjection )
514 0 : return pszProjection;
515 : else
516 0 : return GDALPamDataset::GetProjectionRef();
517 : }
518 :
519 : /************************************************************************/
520 : /* GetGeoTransform() */
521 : /************************************************************************/
522 :
523 24 : CPLErr PAuxDataset::GetGeoTransform( double * padfGeoTransform )
524 :
525 : {
526 24 : if( CSLFetchNameValue(papszAuxLines, "UpLeftX") != NULL
527 : && CSLFetchNameValue(papszAuxLines, "UpLeftY") != NULL
528 : && CSLFetchNameValue(papszAuxLines, "LoRightX") != NULL
529 : && CSLFetchNameValue(papszAuxLines, "LoRightY") != NULL )
530 : {
531 : double dfUpLeftX, dfUpLeftY, dfLoRightX, dfLoRightY;
532 :
533 24 : dfUpLeftX = atof(CSLFetchNameValue(papszAuxLines, "UpLeftX" ));
534 24 : dfUpLeftY = atof(CSLFetchNameValue(papszAuxLines, "UpLeftY" ));
535 24 : dfLoRightX = atof(CSLFetchNameValue(papszAuxLines, "LoRightX" ));
536 24 : dfLoRightY = atof(CSLFetchNameValue(papszAuxLines, "LoRightY" ));
537 :
538 24 : padfGeoTransform[0] = dfUpLeftX;
539 24 : padfGeoTransform[1] = (dfLoRightX - dfUpLeftX) / GetRasterXSize();
540 24 : padfGeoTransform[2] = 0.0;
541 24 : padfGeoTransform[3] = dfUpLeftY;
542 24 : padfGeoTransform[4] = 0.0;
543 24 : padfGeoTransform[5] = (dfLoRightY - dfUpLeftY) / GetRasterYSize();
544 :
545 24 : return CE_None;
546 : }
547 : else
548 : {
549 0 : padfGeoTransform[0] = 0.0;
550 0 : padfGeoTransform[1] = 1.0;
551 0 : padfGeoTransform[2] = 0.0;
552 0 : padfGeoTransform[3] = 0.0;
553 0 : padfGeoTransform[4] = 0.0;
554 0 : padfGeoTransform[5] = 1.0;
555 :
556 0 : return CE_Failure;
557 : }
558 : }
559 :
560 : /************************************************************************/
561 : /* SetGeoTransform() */
562 : /************************************************************************/
563 :
564 42 : CPLErr PAuxDataset::SetGeoTransform( double * padfGeoTransform )
565 :
566 : {
567 : char szUpLeftX[128];
568 : char szUpLeftY[128];
569 : char szLoRightX[128];
570 : char szLoRightY[128];
571 :
572 156 : if( ABS(padfGeoTransform[0]) < 181
573 76 : && ABS(padfGeoTransform[1]) < 1 )
574 : {
575 38 : sprintf( szUpLeftX, "%.12f", padfGeoTransform[0] );
576 38 : sprintf( szUpLeftY, "%.12f", padfGeoTransform[3] );
577 : sprintf( szLoRightX, "%.12f",
578 38 : padfGeoTransform[0] + padfGeoTransform[1] * GetRasterXSize() );
579 : sprintf( szLoRightY, "%.12f",
580 38 : padfGeoTransform[3] + padfGeoTransform[5] * GetRasterYSize() );
581 : }
582 : else
583 : {
584 4 : sprintf( szUpLeftX, "%.3f", padfGeoTransform[0] );
585 4 : sprintf( szUpLeftY, "%.3f", padfGeoTransform[3] );
586 : sprintf( szLoRightX, "%.3f",
587 4 : padfGeoTransform[0] + padfGeoTransform[1] * GetRasterXSize() );
588 : sprintf( szLoRightY, "%.3f",
589 4 : padfGeoTransform[3] + padfGeoTransform[5] * GetRasterYSize() );
590 : }
591 :
592 : papszAuxLines = CSLSetNameValue( papszAuxLines,
593 42 : "UpLeftX", szUpLeftX );
594 : papszAuxLines = CSLSetNameValue( papszAuxLines,
595 42 : "UpLeftY", szUpLeftY );
596 : papszAuxLines = CSLSetNameValue( papszAuxLines,
597 42 : "LoRightX", szLoRightX );
598 : papszAuxLines = CSLSetNameValue( papszAuxLines,
599 42 : "LoRightY", szLoRightY );
600 :
601 42 : bAuxUpdated = TRUE;
602 :
603 42 : return CE_None;
604 : }
605 :
606 : /************************************************************************/
607 : /* Open() */
608 : /************************************************************************/
609 :
610 22876 : GDALDataset *PAuxDataset::Open( GDALOpenInfo * poOpenInfo )
611 :
612 : {
613 : int i;
614 22876 : CPLString osAuxFilename;
615 : char **papszTokens;
616 22876 : CPLString osTarget;
617 :
618 22876 : if( poOpenInfo->nHeaderBytes < 1 )
619 21302 : return NULL;
620 :
621 : /* -------------------------------------------------------------------- */
622 : /* If this is an .aux file, fetch out and form the name of the */
623 : /* file it references. */
624 : /* -------------------------------------------------------------------- */
625 :
626 1574 : osTarget = poOpenInfo->pszFilename;
627 :
628 1574 : if( EQUAL(CPLGetExtension( poOpenInfo->pszFilename ),"aux")
629 : && EQUALN((const char *) poOpenInfo->pabyHeader,"AuxilaryTarget: ",16))
630 : {
631 : char szAuxTarget[1024];
632 : char *pszPath;
633 4 : const char *pszSrc = (const char *) poOpenInfo->pabyHeader+16;
634 :
635 184 : for( i = 0;
636 136 : pszSrc[i] != 10 && pszSrc[i] != 13 && pszSrc[i] != '\0'
637 : && i < (int) sizeof(szAuxTarget)-1;
638 : i++ )
639 : {
640 44 : szAuxTarget[i] = pszSrc[i];
641 : }
642 4 : szAuxTarget[i] = '\0';
643 :
644 4 : pszPath = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename));
645 4 : osTarget = CPLFormFilename(pszPath, szAuxTarget, NULL);
646 4 : CPLFree(pszPath);
647 : }
648 :
649 : /* -------------------------------------------------------------------- */
650 : /* Now we need to tear apart the filename to form a .aux */
651 : /* filename. */
652 : /* -------------------------------------------------------------------- */
653 1574 : osAuxFilename = CPLResetExtension(osTarget,"aux");
654 :
655 : /* -------------------------------------------------------------------- */
656 : /* Do we have a .aux file? */
657 : /* -------------------------------------------------------------------- */
658 1574 : if( poOpenInfo->papszSiblingFiles != NULL
659 : && CSLFindString( poOpenInfo->papszSiblingFiles,
660 : CPLGetFilename(osAuxFilename) ) == -1 )
661 : {
662 1488 : return NULL;
663 : }
664 :
665 : VSILFILE *fp;
666 :
667 86 : fp = VSIFOpenL( osAuxFilename, "r" );
668 86 : if( fp == NULL )
669 : {
670 8 : osAuxFilename = CPLResetExtension(osTarget,"AUX");
671 8 : fp = VSIFOpenL( osAuxFilename, "r" );
672 : }
673 :
674 86 : if( fp == NULL )
675 8 : return NULL;
676 :
677 : /* -------------------------------------------------------------------- */
678 : /* Is this file a PCI .aux file? Check the first line for the */
679 : /* telltale AuxilaryTarget keyword. */
680 : /* */
681 : /* At this point we should be verifying that it refers to our */
682 : /* binary file, but that is a pretty involved test. */
683 : /* -------------------------------------------------------------------- */
684 : const char * pszLine;
685 :
686 78 : pszLine = CPLReadLineL( fp );
687 :
688 78 : VSIFCloseL( fp );
689 :
690 78 : if( pszLine == NULL
691 : || (!EQUALN(pszLine,"AuxilaryTarget",14)
692 : && !EQUALN(pszLine,"AuxiliaryTarget",15)) )
693 : {
694 0 : return NULL;
695 : }
696 :
697 : /* -------------------------------------------------------------------- */
698 : /* Create a corresponding GDALDataset. */
699 : /* -------------------------------------------------------------------- */
700 : PAuxDataset *poDS;
701 :
702 78 : poDS = new PAuxDataset();
703 :
704 : /* -------------------------------------------------------------------- */
705 : /* Load the .aux file into a string list suitable to be */
706 : /* searched with CSLFetchNameValue(). */
707 : /* -------------------------------------------------------------------- */
708 156 : poDS->papszAuxLines = CSLLoad( osAuxFilename );
709 78 : poDS->pszAuxFilename = CPLStrdup(osAuxFilename);
710 :
711 : /* -------------------------------------------------------------------- */
712 : /* Find the RawDefinition line to establish overall parameters. */
713 : /* -------------------------------------------------------------------- */
714 78 : pszLine = CSLFetchNameValue(poDS->papszAuxLines, "RawDefinition");
715 :
716 : // It seems PCI now writes out .aux files without RawDefinition in
717 : // some cases. See bug 947.
718 78 : if( pszLine == NULL )
719 : {
720 0 : delete poDS;
721 0 : return NULL;
722 : }
723 :
724 78 : papszTokens = CSLTokenizeString(pszLine);
725 :
726 78 : if( CSLCount(papszTokens) < 3 )
727 : {
728 : CPLError( CE_Failure, CPLE_AppDefined,
729 : "RawDefinition missing or corrupt in %s.",
730 0 : poOpenInfo->pszFilename );
731 0 : CSLDestroy( papszTokens );
732 0 : return NULL;
733 : }
734 :
735 78 : poDS->nRasterXSize = atoi(papszTokens[0]);
736 78 : poDS->nRasterYSize = atoi(papszTokens[1]);
737 78 : poDS->nBands = atoi(papszTokens[2]);
738 78 : poDS->eAccess = poOpenInfo->eAccess;
739 :
740 78 : CSLDestroy( papszTokens );
741 :
742 78 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
743 : !GDALCheckBandCount(poDS->nBands, FALSE))
744 : {
745 4 : delete poDS;
746 4 : return NULL;
747 : }
748 :
749 : /* -------------------------------------------------------------------- */
750 : /* Open the file. */
751 : /* -------------------------------------------------------------------- */
752 74 : if( poOpenInfo->eAccess == GA_Update )
753 : {
754 42 : poDS->fpImage = VSIFOpenL( osTarget, "rb+" );
755 :
756 42 : if( poDS->fpImage == NULL )
757 : {
758 : CPLError( CE_Failure, CPLE_OpenFailed,
759 : "File %s is missing or read-only, check permissions.",
760 0 : osTarget.c_str() );
761 :
762 0 : delete poDS;
763 0 : return NULL;
764 : }
765 : }
766 : else
767 : {
768 32 : poDS->fpImage = VSIFOpenL( osTarget, "rb" );
769 :
770 32 : if( poDS->fpImage == NULL )
771 : {
772 : CPLError( CE_Failure, CPLE_OpenFailed,
773 : "File %s is missing or unreadable.",
774 0 : osTarget.c_str() );
775 :
776 0 : delete poDS;
777 0 : return NULL;
778 : }
779 : }
780 :
781 : /* -------------------------------------------------------------------- */
782 : /* Collect raw definitions of each channel and create */
783 : /* corresponding bands. */
784 : /* -------------------------------------------------------------------- */
785 74 : int iBand = 0;
786 238 : for( i = 0; i < poDS->nBands; i++ )
787 : {
788 : char szDefnName[32];
789 : GDALDataType eType;
790 164 : int bNative = TRUE;
791 :
792 164 : sprintf( szDefnName, "ChanDefinition-%d", i+1 );
793 :
794 164 : pszLine = CSLFetchNameValue(poDS->papszAuxLines, szDefnName);
795 164 : if (pszLine == NULL)
796 : {
797 0 : continue;
798 : }
799 :
800 164 : papszTokens = CSLTokenizeString(pszLine);
801 164 : if( CSLCount(papszTokens) < 4 )
802 : {
803 : // Skip the band with broken description
804 0 : CSLDestroy( papszTokens );
805 0 : continue;
806 : }
807 :
808 164 : if( EQUAL(papszTokens[0],"16U") )
809 30 : eType = GDT_UInt16;
810 134 : else if( EQUAL(papszTokens[0],"16S") )
811 18 : eType = GDT_Int16;
812 116 : else if( EQUAL(papszTokens[0],"32R") )
813 18 : eType = GDT_Float32;
814 : else
815 98 : eType = GDT_Byte;
816 :
817 164 : if( CSLCount(papszTokens) > 4 )
818 : {
819 : #ifdef CPL_LSB
820 164 : bNative = EQUAL(papszTokens[4],"Swapped");
821 : #else
822 : bNative = EQUAL(papszTokens[4],"Unswapped");
823 : #endif
824 : }
825 :
826 164 : vsi_l_offset nBandOffset = CPLScanUIntBig(papszTokens[1],
827 328 : strlen(papszTokens[1]));
828 164 : int nPixelOffset = atoi(papszTokens[2]);
829 164 : int nLineOffset = atoi(papszTokens[3]);
830 :
831 164 : if (nPixelOffset <= 0 || nLineOffset <= 0)
832 : {
833 : // Skip the band with broken offsets
834 0 : CSLDestroy( papszTokens );
835 0 : continue;
836 : }
837 :
838 : poDS->SetBand( iBand+1,
839 : new PAuxRasterBand( poDS, iBand+1, poDS->fpImage,
840 : nBandOffset,
841 : nPixelOffset,
842 164 : nLineOffset, eType, bNative ) );
843 164 : iBand ++;
844 :
845 164 : CSLDestroy( papszTokens );
846 : }
847 :
848 74 : poDS->nBands = iBand;
849 :
850 : /* -------------------------------------------------------------------- */
851 : /* Get the projection. */
852 : /* -------------------------------------------------------------------- */
853 : const char *pszMapUnits, *pszProjParms;
854 :
855 74 : pszMapUnits = CSLFetchNameValue( poDS->papszAuxLines, "MapUnits" );
856 74 : pszProjParms = CSLFetchNameValue( poDS->papszAuxLines, "ProjParms" );
857 :
858 74 : if( pszMapUnits != NULL )
859 0 : poDS->pszProjection = poDS->PCI2WKT( pszMapUnits, pszProjParms );
860 :
861 : /* -------------------------------------------------------------------- */
862 : /* Initialize any PAM information. */
863 : /* -------------------------------------------------------------------- */
864 74 : poDS->SetDescription( osTarget );
865 74 : poDS->TryLoadXML();
866 :
867 : /* -------------------------------------------------------------------- */
868 : /* Check for overviews. */
869 : /* -------------------------------------------------------------------- */
870 74 : poDS->oOvManager.Initialize( poDS, osTarget );
871 :
872 74 : poDS->ScanForGCPs();
873 74 : poDS->bAuxUpdated = FALSE;
874 :
875 74 : return( poDS );
876 : }
877 :
878 : /************************************************************************/
879 : /* Create() */
880 : /************************************************************************/
881 :
882 90 : GDALDataset *PAuxDataset::Create( const char * pszFilename,
883 : int nXSize, int nYSize, int nBands,
884 : GDALDataType eType,
885 : char **papszOptions )
886 :
887 : {
888 : char *pszAuxFilename;
889 :
890 90 : const char *pszInterleave = CSLFetchNameValue( papszOptions, "INTERLEAVE" );
891 90 : if( pszInterleave == NULL )
892 90 : pszInterleave = "BAND";
893 :
894 : /* -------------------------------------------------------------------- */
895 : /* Verify input options. */
896 : /* -------------------------------------------------------------------- */
897 90 : if( eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16
898 : && eType != GDT_Int16 )
899 : {
900 : CPLError( CE_Failure, CPLE_AppDefined,
901 : "Attempt to create PCI .Aux labelled dataset with an illegal\n"
902 : "data type (%s).\n",
903 42 : GDALGetDataTypeName(eType) );
904 :
905 42 : return NULL;
906 : }
907 :
908 : /* -------------------------------------------------------------------- */
909 : /* Sum the sizes of the band pixel types. */
910 : /* -------------------------------------------------------------------- */
911 48 : int nPixelSizeSum = 0;
912 : int iBand;
913 :
914 146 : for( iBand = 0; iBand < nBands; iBand++ )
915 98 : nPixelSizeSum += (GDALGetDataTypeSize(eType)/8);
916 :
917 : /* -------------------------------------------------------------------- */
918 : /* Try to create the file. */
919 : /* -------------------------------------------------------------------- */
920 : VSILFILE *fp;
921 :
922 48 : fp = VSIFOpenL( pszFilename, "w" );
923 :
924 48 : if( fp == NULL )
925 : {
926 : CPLError( CE_Failure, CPLE_OpenFailed,
927 : "Attempt to create file `%s' failed.\n",
928 4 : pszFilename );
929 4 : return NULL;
930 : }
931 :
932 : /* -------------------------------------------------------------------- */
933 : /* Just write out a couple of bytes to establish the binary */
934 : /* file, and then close it. */
935 : /* -------------------------------------------------------------------- */
936 44 : VSIFWriteL( (void *) "\0\0", 2, 1, fp );
937 44 : VSIFCloseL( fp );
938 :
939 : /* -------------------------------------------------------------------- */
940 : /* Create the aux filename. */
941 : /* -------------------------------------------------------------------- */
942 44 : pszAuxFilename = (char *) CPLMalloc(strlen(pszFilename)+5);
943 44 : strcpy( pszAuxFilename, pszFilename );;
944 :
945 1132 : for( int i = strlen(pszAuxFilename)-1; i > 0; i-- )
946 : {
947 1092 : if( pszAuxFilename[i] == '.' )
948 : {
949 4 : pszAuxFilename[i] = '\0';
950 4 : break;
951 : }
952 : }
953 :
954 44 : strcat( pszAuxFilename, ".aux" );
955 :
956 : /* -------------------------------------------------------------------- */
957 : /* Open the file. */
958 : /* -------------------------------------------------------------------- */
959 44 : fp = VSIFOpenL( pszAuxFilename, "wt" );
960 44 : if( fp == NULL )
961 : {
962 : CPLError( CE_Failure, CPLE_OpenFailed,
963 : "Attempt to create file `%s' failed.\n",
964 0 : pszAuxFilename );
965 0 : return NULL;
966 : }
967 44 : CPLFree( pszAuxFilename );
968 :
969 : /* -------------------------------------------------------------------- */
970 : /* We need to write out the original filename but without any */
971 : /* path components in the AuxilaryTarget line. Do so now. */
972 : /* -------------------------------------------------------------------- */
973 : int iStart;
974 :
975 44 : iStart = strlen(pszFilename)-1;
976 336 : while( iStart > 0 && pszFilename[iStart-1] != '/'
977 124 : && pszFilename[iStart-1] != '\\' )
978 124 : iStart--;
979 :
980 44 : VSIFPrintfL( fp, "AuxilaryTarget: %s\n", pszFilename + iStart );
981 :
982 : /* -------------------------------------------------------------------- */
983 : /* Write out the raw definition for the dataset as a whole. */
984 : /* -------------------------------------------------------------------- */
985 : VSIFPrintfL( fp, "RawDefinition: %d %d %d\n",
986 44 : nXSize, nYSize, nBands );
987 :
988 : /* -------------------------------------------------------------------- */
989 : /* Write out a definition for each band. We always write band */
990 : /* sequential files for now as these are pretty efficiently */
991 : /* handled by GDAL. */
992 : /* -------------------------------------------------------------------- */
993 44 : vsi_l_offset nImgOffset = 0;
994 :
995 138 : for( iBand = 0; iBand < nBands; iBand++ )
996 : {
997 : const char *pszTypeName;
998 : int nPixelOffset, nLineOffset;
999 : vsi_l_offset nNextImgOffset;
1000 :
1001 : /* -------------------------------------------------------------------- */
1002 : /* Establish our file layout based on supplied interleaving. */
1003 : /* -------------------------------------------------------------------- */
1004 94 : if( EQUAL(pszInterleave,"LINE") )
1005 : {
1006 0 : nPixelOffset = GDALGetDataTypeSize(eType)/8;
1007 0 : nLineOffset = nXSize * nPixelSizeSum;
1008 0 : nNextImgOffset = nImgOffset + nPixelOffset * nXSize;
1009 : }
1010 94 : else if( EQUAL(pszInterleave,"PIXEL") )
1011 : {
1012 0 : nPixelOffset = nPixelSizeSum;
1013 0 : nLineOffset = nXSize * nPixelOffset;
1014 0 : nNextImgOffset = nImgOffset + (GDALGetDataTypeSize(eType)/8);
1015 : }
1016 : else /* default to band */
1017 : {
1018 94 : nPixelOffset = GDALGetDataTypeSize(eType)/8;
1019 94 : nLineOffset = nXSize * nPixelOffset;
1020 94 : nNextImgOffset = nImgOffset + nYSize * (vsi_l_offset) nLineOffset;
1021 : }
1022 :
1023 : /* -------------------------------------------------------------------- */
1024 : /* Write out line indicating layout. */
1025 : /* -------------------------------------------------------------------- */
1026 94 : if( eType == GDT_Float32 )
1027 10 : pszTypeName = "32R";
1028 84 : else if( eType == GDT_Int16 )
1029 10 : pszTypeName = "16S";
1030 74 : else if( eType == GDT_UInt16 )
1031 10 : pszTypeName = "16U";
1032 : else
1033 64 : pszTypeName = "8U";
1034 :
1035 : VSIFPrintfL( fp, "ChanDefinition-%d: %s " CPL_FRMT_GIB " %d %d %s\n",
1036 : iBand+1,
1037 : pszTypeName, (GIntBig) nImgOffset,
1038 : nPixelOffset, nLineOffset,
1039 : #ifdef CPL_LSB
1040 : "Swapped"
1041 : #else
1042 : "Unswapped"
1043 : #endif
1044 94 : );
1045 :
1046 94 : nImgOffset = nNextImgOffset;
1047 : }
1048 :
1049 : /* -------------------------------------------------------------------- */
1050 : /* Cleanup */
1051 : /* -------------------------------------------------------------------- */
1052 44 : VSIFCloseL( fp );
1053 :
1054 44 : return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
1055 : }
1056 :
1057 : /************************************************************************/
1058 : /* PAuxDelete() */
1059 : /************************************************************************/
1060 :
1061 4 : CPLErr PAuxDelete( const char * pszBasename )
1062 :
1063 : {
1064 : VSILFILE *fp;
1065 : const char *pszLine;
1066 :
1067 4 : fp = VSIFOpenL( CPLResetExtension( pszBasename, "aux" ), "r" );
1068 4 : if( fp == NULL )
1069 : {
1070 : CPLError( CE_Failure, CPLE_AppDefined,
1071 : "%s does not appear to be a PAux dataset, there is no .aux file.",
1072 0 : pszBasename );
1073 0 : return CE_Failure;
1074 : }
1075 :
1076 4 : pszLine = CPLReadLineL( fp );
1077 4 : VSIFCloseL( fp );
1078 :
1079 4 : if( pszLine == NULL || !EQUALN(pszLine,"AuxilaryTarget",14) )
1080 : {
1081 : CPLError( CE_Failure, CPLE_AppDefined,
1082 : "%s does not appear to be a PAux dataset,\n"
1083 : "the .aux file does not start with AuxilaryTarget",
1084 0 : pszBasename );
1085 0 : return CE_Failure;
1086 : }
1087 :
1088 4 : if( VSIUnlink( pszBasename ) != 0 )
1089 : {
1090 : CPLError( CE_Failure, CPLE_AppDefined,
1091 0 : "OS unlinking file %s.", pszBasename );
1092 0 : return CE_Failure;
1093 : }
1094 :
1095 4 : VSIUnlink( CPLResetExtension( pszBasename, "aux" ) );
1096 :
1097 4 : return CE_None;
1098 : }
1099 :
1100 : /************************************************************************/
1101 : /* GDALRegister_PAux() */
1102 : /************************************************************************/
1103 :
1104 1135 : void GDALRegister_PAux()
1105 :
1106 : {
1107 : GDALDriver *poDriver;
1108 :
1109 1135 : if( GDALGetDriverByName( "PAux" ) == NULL )
1110 : {
1111 1093 : poDriver = new GDALDriver();
1112 :
1113 1093 : poDriver->SetDescription( "PAux" );
1114 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1115 1093 : "PCI .aux Labelled" );
1116 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1117 1093 : "frmt_various.html#PAux" );
1118 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1119 1093 : "Byte Int16 UInt16 Float32" );
1120 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1121 : "<CreationOptionList>"
1122 : " <Option name='INTERLEAVE' type='string-select' default='BAND'>"
1123 : " <Value>BAND</Value>"
1124 : " <Value>LINE</Value>"
1125 : " <Value>PIXEL</Value>"
1126 : " </Option>"
1127 1093 : "</CreationOptionList>" );
1128 :
1129 1093 : poDriver->pfnOpen = PAuxDataset::Open;
1130 1093 : poDriver->pfnCreate = PAuxDataset::Create;
1131 1093 : poDriver->pfnDelete = PAuxDelete;
1132 :
1133 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
1134 : }
1135 1135 : }
1136 :
|