1 : /******************************************************************************
2 : * $Id: pauxdataset.cpp 16706 2009-04-02 03:44:07Z 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 16706 2009-04-02 03:44:07Z 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 : FILE *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, FILE * 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 46 : PAuxRasterBand::PAuxRasterBand( GDALDataset *poDS, int nBand,
118 : FILE * 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 46 : eDataType, bNativeOrder, TRUE )
124 :
125 : {
126 46 : PAuxDataset *poPDS = (PAuxDataset *) poDS;
127 :
128 46 : poCT = NULL;
129 :
130 : /* -------------------------------------------------------------------- */
131 : /* Does this channel have a description? */
132 : /* -------------------------------------------------------------------- */
133 : char szTarget[128];
134 :
135 46 : sprintf( szTarget, "ChanDesc-%d", nBand );
136 46 : 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 46 : sprintf( szTarget, "METADATA_IMG_%d_Class_%d_Color", nBand, 0 );
145 46 : 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 46 : }
178 :
179 : /************************************************************************/
180 : /* ~PAuxRasterBand() */
181 : /************************************************************************/
182 :
183 92 : PAuxRasterBand::~PAuxRasterBand()
184 :
185 : {
186 46 : if( poCT != NULL )
187 0 : delete poCT;
188 92 : }
189 :
190 : /************************************************************************/
191 : /* GetNoDataValue() */
192 : /************************************************************************/
193 :
194 4 : double PAuxRasterBand::GetNoDataValue( int *pbSuccess )
195 :
196 : {
197 4 : PAuxDataset *poPDS = (PAuxDataset *) poDS;
198 : char szTarget[128];
199 : const char *pszLine;
200 :
201 4 : sprintf( szTarget, "METADATA_IMG_%d_NO_DATA_VALUE", nBand );
202 :
203 4 : pszLine = CSLFetchNameValue( poPDS->papszAuxLines, szTarget );
204 :
205 4 : if( pbSuccess != NULL )
206 4 : *pbSuccess = (pszLine != NULL);
207 :
208 4 : if( pszLine == NULL )
209 4 : 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 15 : GDALColorInterp PAuxRasterBand::GetColorInterpretation()
285 :
286 : {
287 15 : if( poCT == NULL )
288 15 : 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 24 : PAuxDataset::PAuxDataset()
304 : {
305 24 : papszAuxLines = NULL;
306 24 : fpImage = NULL;
307 24 : bAuxUpdated = FALSE;
308 24 : pszAuxFilename = NULL;
309 24 : nGCPCount = 0;
310 24 : pasGCPList = NULL;
311 :
312 24 : pszProjection = NULL;
313 24 : pszGCPProjection = NULL;
314 24 : }
315 :
316 : /************************************************************************/
317 : /* ~PAuxDataset() */
318 : /************************************************************************/
319 :
320 48 : PAuxDataset::~PAuxDataset()
321 :
322 : {
323 24 : FlushCache();
324 24 : if( fpImage != NULL )
325 23 : VSIFCloseL( fpImage );
326 :
327 24 : if( bAuxUpdated )
328 : {
329 10 : CSLSetNameValueSeparator( papszAuxLines, ": " );
330 10 : CSLSave( papszAuxLines, pszAuxFilename );
331 : }
332 :
333 24 : CPLFree( pszProjection );
334 :
335 24 : CPLFree( pszGCPProjection );
336 24 : GDALDeinitGCPs( nGCPCount, pasGCPList );
337 24 : CPLFree( pasGCPList );
338 :
339 24 : CPLFree( pszAuxFilename );
340 24 : CSLDestroy( papszAuxLines );
341 48 : }
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 23 : void PAuxDataset::ScanForGCPs()
399 :
400 : {
401 : #define MAX_GCP 256
402 :
403 23 : nGCPCount = 0;
404 23 : 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 23 : pszMapUnits = CSLFetchNameValue( papszAuxLines, "GCP_1_MapUnits" );
412 23 : pszProjParms = CSLFetchNameValue( papszAuxLines, "GCP_1_ProjParms" );
413 :
414 23 : 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 23 : for( i = 0; nGCPCount < MAX_GCP; i++ )
425 : {
426 : char szName[50];
427 : char **papszTokens;
428 :
429 23 : sprintf( szName, "GCP_1_%d", i+1 );
430 23 : if( CSLFetchNameValue( papszAuxLines, szName ) == NULL )
431 23 : 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 23 : }
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 1 : CPLErr PAuxDataset::GetGeoTransform( double * padfGeoTransform )
524 :
525 : {
526 1 : 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 1 : dfUpLeftX = atof(CSLFetchNameValue(papszAuxLines, "UpLeftX" ));
534 1 : dfUpLeftY = atof(CSLFetchNameValue(papszAuxLines, "UpLeftY" ));
535 1 : dfLoRightX = atof(CSLFetchNameValue(papszAuxLines, "LoRightX" ));
536 1 : dfLoRightY = atof(CSLFetchNameValue(papszAuxLines, "LoRightY" ));
537 :
538 1 : padfGeoTransform[0] = dfUpLeftX;
539 1 : padfGeoTransform[1] = (dfLoRightX - dfUpLeftX) / GetRasterXSize();
540 1 : padfGeoTransform[2] = 0.0;
541 1 : padfGeoTransform[3] = dfUpLeftY;
542 1 : padfGeoTransform[4] = 0.0;
543 1 : padfGeoTransform[5] = (dfLoRightY - dfUpLeftY) / GetRasterYSize();
544 :
545 1 : 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 10 : 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 34 : if( ABS(padfGeoTransform[0]) < 181
573 16 : && ABS(padfGeoTransform[1]) < 1 )
574 : {
575 8 : sprintf( szUpLeftX, "%.12f", padfGeoTransform[0] );
576 8 : sprintf( szUpLeftY, "%.12f", padfGeoTransform[3] );
577 : sprintf( szLoRightX, "%.12f",
578 8 : padfGeoTransform[0] + padfGeoTransform[1] * GetRasterXSize() );
579 : sprintf( szLoRightY, "%.12f",
580 8 : padfGeoTransform[3] + padfGeoTransform[5] * GetRasterYSize() );
581 : }
582 : else
583 : {
584 2 : sprintf( szUpLeftX, "%.3f", padfGeoTransform[0] );
585 2 : sprintf( szUpLeftY, "%.3f", padfGeoTransform[3] );
586 : sprintf( szLoRightX, "%.3f",
587 2 : padfGeoTransform[0] + padfGeoTransform[1] * GetRasterXSize() );
588 : sprintf( szLoRightY, "%.3f",
589 2 : padfGeoTransform[3] + padfGeoTransform[5] * GetRasterYSize() );
590 : }
591 :
592 : papszAuxLines = CSLSetNameValue( papszAuxLines,
593 10 : "UpLeftX", szUpLeftX );
594 : papszAuxLines = CSLSetNameValue( papszAuxLines,
595 10 : "UpLeftY", szUpLeftY );
596 : papszAuxLines = CSLSetNameValue( papszAuxLines,
597 10 : "LoRightX", szLoRightX );
598 : papszAuxLines = CSLSetNameValue( papszAuxLines,
599 10 : "LoRightY", szLoRightY );
600 :
601 10 : bAuxUpdated = TRUE;
602 :
603 10 : return CE_None;
604 : }
605 :
606 : /************************************************************************/
607 : /* Open() */
608 : /************************************************************************/
609 :
610 8626 : GDALDataset *PAuxDataset::Open( GDALOpenInfo * poOpenInfo )
611 :
612 : {
613 : int i;
614 8626 : CPLString osAuxFilename;
615 : char **papszTokens;
616 8626 : CPLString osTarget;
617 :
618 8626 : if( poOpenInfo->nHeaderBytes < 1 )
619 8292 : 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 334 : osTarget = poOpenInfo->pszFilename;
627 :
628 334 : if( EQUAL(CPLGetExtension( poOpenInfo->pszFilename ),"aux")
629 : && EQUALN((const char *) poOpenInfo->pabyHeader,"AuxilaryTarget: ",16))
630 : {
631 : char szAuxTarget[1024];
632 : char *pszPath;
633 2 : const char *pszSrc = (const char *) poOpenInfo->pabyHeader+16;
634 :
635 92 : for( i = 0;
636 68 : pszSrc[i] != 10 && pszSrc[i] != 13 && pszSrc[i] != '\0'
637 : && i < (int) sizeof(szAuxTarget)-1;
638 : i++ )
639 : {
640 22 : szAuxTarget[i] = pszSrc[i];
641 : }
642 2 : szAuxTarget[i] = '\0';
643 :
644 2 : pszPath = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename));
645 2 : osTarget = CPLFormFilename(pszPath, szAuxTarget, NULL);
646 2 : CPLFree(pszPath);
647 : }
648 :
649 : /* -------------------------------------------------------------------- */
650 : /* Now we need to tear apart the filename to form a .aux */
651 : /* filename. */
652 : /* -------------------------------------------------------------------- */
653 334 : osAuxFilename = CPLResetExtension(osTarget,"aux");
654 :
655 : /* -------------------------------------------------------------------- */
656 : /* Do we have a .aux file? */
657 : /* -------------------------------------------------------------------- */
658 334 : if( poOpenInfo->papszSiblingFiles != NULL
659 : && CSLFindString( poOpenInfo->papszSiblingFiles,
660 : CPLGetFilename(osAuxFilename) ) == -1 )
661 : {
662 283 : return NULL;
663 : }
664 :
665 : FILE *fp;
666 :
667 51 : fp = VSIFOpenL( osAuxFilename, "r" );
668 51 : if( fp == NULL )
669 : {
670 27 : osAuxFilename = CPLResetExtension(osTarget,"AUX");
671 27 : fp = VSIFOpenL( osAuxFilename, "r" );
672 : }
673 :
674 51 : if( fp == NULL )
675 27 : 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 24 : pszLine = CPLReadLineL( fp );
687 :
688 24 : VSIFCloseL( fp );
689 :
690 24 : 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 24 : poDS = new PAuxDataset();
703 :
704 : /* -------------------------------------------------------------------- */
705 : /* Load the .aux file into a string list suitable to be */
706 : /* searched with CSLFetchNameValue(). */
707 : /* -------------------------------------------------------------------- */
708 48 : poDS->papszAuxLines = CSLLoad( osAuxFilename );
709 24 : poDS->pszAuxFilename = CPLStrdup(osAuxFilename);
710 :
711 : /* -------------------------------------------------------------------- */
712 : /* Find the RawDefinition line to establish overall parameters. */
713 : /* -------------------------------------------------------------------- */
714 24 : 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 24 : if( pszLine == NULL )
719 : {
720 0 : delete poDS;
721 0 : return NULL;
722 : }
723 :
724 24 : papszTokens = CSLTokenizeString(pszLine);
725 :
726 24 : 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 24 : poDS->nRasterXSize = atoi(papszTokens[0]);
736 24 : poDS->nRasterYSize = atoi(papszTokens[1]);
737 24 : poDS->nBands = atoi(papszTokens[2]);
738 24 : poDS->eAccess = poOpenInfo->eAccess;
739 :
740 24 : CSLDestroy( papszTokens );
741 :
742 24 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
743 : !GDALCheckBandCount(poDS->nBands, FALSE))
744 : {
745 1 : delete poDS;
746 1 : return NULL;
747 : }
748 :
749 : /* -------------------------------------------------------------------- */
750 : /* Open the file. */
751 : /* -------------------------------------------------------------------- */
752 23 : if( poOpenInfo->eAccess == GA_Update )
753 : {
754 18 : poDS->fpImage = VSIFOpenL( osTarget, "rb+" );
755 :
756 18 : 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 5 : poDS->fpImage = VSIFOpenL( osTarget, "rb" );
769 :
770 5 : 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 23 : int iBand = 0;
786 69 : for( i = 0; i < poDS->nBands; i++ )
787 : {
788 : char szDefnName[32];
789 : GDALDataType eType;
790 46 : int bNative = TRUE;
791 :
792 46 : sprintf( szDefnName, "ChanDefinition-%d", i+1 );
793 :
794 46 : pszLine = CSLFetchNameValue(poDS->papszAuxLines, szDefnName);
795 46 : if (pszLine == NULL)
796 : {
797 0 : continue;
798 : }
799 :
800 46 : papszTokens = CSLTokenizeString(pszLine);
801 46 : if( CSLCount(papszTokens) < 4 )
802 : {
803 : // Skip the band with broken description
804 0 : CSLDestroy( papszTokens );
805 0 : continue;
806 : }
807 :
808 46 : if( EQUAL(papszTokens[0],"16U") )
809 8 : eType = GDT_UInt16;
810 38 : else if( EQUAL(papszTokens[0],"16S") )
811 2 : eType = GDT_Int16;
812 36 : else if( EQUAL(papszTokens[0],"32R") )
813 2 : eType = GDT_Float32;
814 : else
815 34 : eType = GDT_Byte;
816 :
817 46 : if( CSLCount(papszTokens) > 4 )
818 : {
819 : #ifdef CPL_LSB
820 46 : bNative = EQUAL(papszTokens[4],"Swapped");
821 : #else
822 : bNative = EQUAL(papszTokens[4],"Unswapped");
823 : #endif
824 : }
825 :
826 46 : vsi_l_offset nBandOffset = CPLScanUIntBig(papszTokens[1],
827 92 : strlen(papszTokens[1]));
828 46 : int nPixelOffset = atoi(papszTokens[2]);
829 46 : int nLineOffset = atoi(papszTokens[3]);
830 :
831 46 : 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 46 : nLineOffset, eType, bNative ) );
843 46 : iBand ++;
844 :
845 46 : CSLDestroy( papszTokens );
846 : }
847 :
848 23 : poDS->nBands = iBand;
849 :
850 : /* -------------------------------------------------------------------- */
851 : /* Get the projection. */
852 : /* -------------------------------------------------------------------- */
853 : const char *pszMapUnits, *pszProjParms;
854 :
855 23 : pszMapUnits = CSLFetchNameValue( poDS->papszAuxLines, "MapUnits" );
856 23 : pszProjParms = CSLFetchNameValue( poDS->papszAuxLines, "ProjParms" );
857 :
858 23 : if( pszMapUnits != NULL )
859 0 : poDS->pszProjection = poDS->PCI2WKT( pszMapUnits, pszProjParms );
860 :
861 : /* -------------------------------------------------------------------- */
862 : /* Initialize any PAM information. */
863 : /* -------------------------------------------------------------------- */
864 23 : poDS->SetDescription( osTarget );
865 23 : poDS->TryLoadXML();
866 :
867 : /* -------------------------------------------------------------------- */
868 : /* Check for overviews. */
869 : /* -------------------------------------------------------------------- */
870 23 : poDS->oOvManager.Initialize( poDS, osTarget );
871 :
872 23 : poDS->ScanForGCPs();
873 23 : poDS->bAuxUpdated = FALSE;
874 :
875 23 : return( poDS );
876 : }
877 :
878 : /************************************************************************/
879 : /* Create() */
880 : /************************************************************************/
881 :
882 33 : GDALDataset *PAuxDataset::Create( const char * pszFilename,
883 : int nXSize, int nYSize, int nBands,
884 : GDALDataType eType,
885 : char ** /* papszParmList */ )
886 :
887 : {
888 : char *pszAuxFilename;
889 :
890 : /* -------------------------------------------------------------------- */
891 : /* Verify input options. */
892 : /* -------------------------------------------------------------------- */
893 33 : if( eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16
894 : && eType != GDT_Int16 )
895 : {
896 : CPLError( CE_Failure, CPLE_AppDefined,
897 : "Attempt to create PCI .Aux labelled dataset with an illegal\n"
898 : "data type (%s).\n",
899 14 : GDALGetDataTypeName(eType) );
900 :
901 14 : return NULL;
902 : }
903 :
904 : /* -------------------------------------------------------------------- */
905 : /* Try to create the file. */
906 : /* -------------------------------------------------------------------- */
907 : FILE *fp;
908 :
909 19 : fp = VSIFOpenL( pszFilename, "w" );
910 :
911 19 : if( fp == NULL )
912 : {
913 : CPLError( CE_Failure, CPLE_OpenFailed,
914 : "Attempt to create file `%s' failed.\n",
915 0 : pszFilename );
916 0 : return NULL;
917 : }
918 :
919 : /* -------------------------------------------------------------------- */
920 : /* Just write out a couple of bytes to establish the binary */
921 : /* file, and then close it. */
922 : /* -------------------------------------------------------------------- */
923 19 : VSIFWriteL( (void *) "\0\0", 2, 1, fp );
924 19 : VSIFCloseL( fp );
925 :
926 : /* -------------------------------------------------------------------- */
927 : /* Create the aux filename. */
928 : /* -------------------------------------------------------------------- */
929 19 : pszAuxFilename = (char *) CPLMalloc(strlen(pszFilename)+5);
930 19 : strcpy( pszAuxFilename, pszFilename );;
931 :
932 479 : for( int i = strlen(pszAuxFilename)-1; i > 0; i-- )
933 : {
934 462 : if( pszAuxFilename[i] == '.' )
935 : {
936 2 : pszAuxFilename[i] = '\0';
937 2 : break;
938 : }
939 : }
940 :
941 19 : strcat( pszAuxFilename, ".aux" );
942 :
943 : /* -------------------------------------------------------------------- */
944 : /* Open the file. */
945 : /* -------------------------------------------------------------------- */
946 19 : fp = VSIFOpenL( pszAuxFilename, "wt" );
947 19 : if( fp == NULL )
948 : {
949 : CPLError( CE_Failure, CPLE_OpenFailed,
950 : "Attempt to create file `%s' failed.\n",
951 0 : pszAuxFilename );
952 0 : return NULL;
953 : }
954 19 : CPLFree( pszAuxFilename );
955 :
956 : /* -------------------------------------------------------------------- */
957 : /* We need to write out the original filename but without any */
958 : /* path components in the AuxilaryTarget line. Do so now. */
959 : /* -------------------------------------------------------------------- */
960 : int iStart;
961 :
962 19 : iStart = strlen(pszFilename)-1;
963 150 : while( iStart > 0 && pszFilename[iStart-1] != '/'
964 56 : && pszFilename[iStart-1] != '\\' )
965 56 : iStart--;
966 :
967 19 : VSIFPrintfL( fp, "AuxilaryTarget: %s\n", pszFilename + iStart );
968 :
969 : /* -------------------------------------------------------------------- */
970 : /* Write out the raw definition for the dataset as a whole. */
971 : /* -------------------------------------------------------------------- */
972 : VSIFPrintfL( fp, "RawDefinition: %d %d %d\n",
973 19 : nXSize, nYSize, nBands );
974 :
975 : /* -------------------------------------------------------------------- */
976 : /* Write out a definition for each band. We always write band */
977 : /* sequential files for now as these are pretty efficiently */
978 : /* handled by GDAL. */
979 : /* -------------------------------------------------------------------- */
980 19 : vsi_l_offset nImgOffset = 0;
981 :
982 57 : for( int iBand = 0; iBand < nBands; iBand++ )
983 : {
984 : const char *pszTypeName;
985 : char szImgOffset[64];
986 : int nPixelOffset, nLineOffset, nChars;
987 :
988 38 : nPixelOffset = GDALGetDataTypeSize(eType)/8;
989 38 : nLineOffset = nXSize * nPixelOffset;
990 :
991 38 : if( eType == GDT_Float32 )
992 2 : pszTypeName = "32R";
993 36 : else if( eType == GDT_Int16 )
994 2 : pszTypeName = "16S";
995 34 : else if( eType == GDT_UInt16 )
996 2 : pszTypeName = "16U";
997 : else
998 32 : pszTypeName = "8U";
999 :
1000 38 : nChars = CPLPrintUIntBig( szImgOffset, nImgOffset, 63 );
1001 38 : szImgOffset[nChars] = '\0';
1002 :
1003 : VSIFPrintfL( fp, "ChanDefinition-%d: %s %s %d %d %s\n", iBand+1,
1004 : pszTypeName, strpbrk(szImgOffset, "-.0123456789"),
1005 : nPixelOffset, nLineOffset,
1006 : #ifdef CPL_LSB
1007 : "Swapped"
1008 : #else
1009 : "Unswapped"
1010 : #endif
1011 38 : );
1012 :
1013 38 : nImgOffset += (vsi_l_offset)nYSize * nLineOffset;
1014 : }
1015 :
1016 : /* -------------------------------------------------------------------- */
1017 : /* Cleanup */
1018 : /* -------------------------------------------------------------------- */
1019 19 : VSIFCloseL( fp );
1020 :
1021 19 : return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
1022 : }
1023 :
1024 : /************************************************************************/
1025 : /* PAuxDelete() */
1026 : /************************************************************************/
1027 :
1028 2 : CPLErr PAuxDelete( const char * pszBasename )
1029 :
1030 : {
1031 : FILE *fp;
1032 : const char *pszLine;
1033 :
1034 2 : fp = VSIFOpenL( CPLResetExtension( pszBasename, "aux" ), "r" );
1035 2 : if( fp == NULL )
1036 : {
1037 : CPLError( CE_Failure, CPLE_AppDefined,
1038 : "%s does not appear to be a PAux dataset, there is no .aux file.",
1039 0 : pszBasename );
1040 0 : return CE_Failure;
1041 : }
1042 :
1043 2 : pszLine = CPLReadLineL( fp );
1044 2 : VSIFCloseL( fp );
1045 :
1046 2 : if( pszLine == NULL || !EQUALN(pszLine,"AuxilaryTarget",14) )
1047 : {
1048 : CPLError( CE_Failure, CPLE_AppDefined,
1049 : "%s does not appear to be a PAux dataset,\n"
1050 : "the .aux file does not start with AuxilaryTarget",
1051 0 : pszBasename );
1052 0 : return CE_Failure;
1053 : }
1054 :
1055 2 : if( VSIUnlink( pszBasename ) != 0 )
1056 : {
1057 : CPLError( CE_Failure, CPLE_AppDefined,
1058 0 : "OS unlinking file %s.", pszBasename );
1059 0 : return CE_Failure;
1060 : }
1061 :
1062 2 : VSIUnlink( CPLResetExtension( pszBasename, "aux" ) );
1063 :
1064 2 : return CE_None;
1065 : }
1066 :
1067 : /************************************************************************/
1068 : /* GDALRegister_PAux() */
1069 : /************************************************************************/
1070 :
1071 338 : void GDALRegister_PAux()
1072 :
1073 : {
1074 : GDALDriver *poDriver;
1075 :
1076 338 : if( GDALGetDriverByName( "PAux" ) == NULL )
1077 : {
1078 336 : poDriver = new GDALDriver();
1079 :
1080 336 : poDriver->SetDescription( "PAux" );
1081 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1082 336 : "PCI .aux Labelled" );
1083 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1084 336 : "frmt_various.html#PAux" );
1085 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1086 336 : "Byte Int16 UInt16 Float32" );
1087 :
1088 336 : poDriver->pfnOpen = PAuxDataset::Open;
1089 336 : poDriver->pfnCreate = PAuxDataset::Create;
1090 336 : poDriver->pfnDelete = PAuxDelete;
1091 :
1092 336 : GetGDALDriverManager()->RegisterDriver( poDriver );
1093 : }
1094 338 : }
1095 :
|