LCOV - code coverage report
Current view: directory - gcore - gdaljp2metadata.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 421 295 70.1 %
Date: 2012-12-26 Functions: 17 13 76.5 %

       1                 : /******************************************************************************
       2                 :  * $Id: gdaljp2metadata.cpp 24404 2012-05-11 19:44:08Z aboudreault $
       3                 :  *
       4                 :  * Project:  GDAL 
       5                 :  * Purpose:  GDALJP2Metadata - Read GeoTIFF and/or GML georef info.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
      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 "gdaljp2metadata.h"
      31                 : #include "cpl_string.h"
      32                 : #include "cpl_minixml.h"
      33                 : #include "ogr_spatialref.h"
      34                 : #include "ogr_geometry.h"
      35                 : #include "ogr_api.h"
      36                 : #include "gt_wkt_srs_for_gdal.h"
      37                 : 
      38                 : CPL_CVSID("$Id: gdaljp2metadata.cpp 24404 2012-05-11 19:44:08Z aboudreault $");
      39                 : 
      40                 : static const unsigned char msi_uuid2[16] =
      41                 : {0xb1,0x4b,0xf8,0xbd,0x08,0x3d,0x4b,0x43,
      42                 :  0xa5,0xae,0x8c,0xd7,0xd5,0xa6,0xce,0x03}; 
      43                 : 
      44                 : static const unsigned char msig_uuid[16] = 
      45                 : { 0x96,0xA9,0xF1,0xF1,0xDC,0x98,0x40,0x2D,
      46                 :   0xA7,0xAE,0xD6,0x8E,0x34,0x45,0x18,0x09 };
      47                 : 
      48                 : static const unsigned char xmp_uuid[16] =
      49                 : { 0xBE,0x7A,0xCF,0xCB,0x97,0xA9,0x42,0xE8,
      50                 :   0x9C,0x71,0x99,0x94,0x91,0xE3,0xAF,0xAC};
      51                 : 
      52                 : /************************************************************************/
      53                 : /*                          GDALJP2Metadata()                           */
      54                 : /************************************************************************/
      55                 : 
      56             180 : GDALJP2Metadata::GDALJP2Metadata()
      57                 : 
      58                 : {
      59             180 :     pszProjection = NULL;
      60                 : 
      61             180 :     nGCPCount = 0;
      62             180 :     pasGCPList = NULL;
      63                 : 
      64             180 :     papszGMLMetadata = NULL;
      65             180 :     papszMetadata = NULL;
      66                 : 
      67             180 :     nGeoTIFFSize = 0;
      68             180 :     pabyGeoTIFFData = NULL;
      69                 : 
      70             180 :     nMSIGSize = 0;
      71             180 :     pabyMSIGData = NULL;
      72                 : 
      73             180 :     pszXMPMetadata = NULL;
      74                 : 
      75             180 :     bHaveGeoTransform = FALSE;
      76             180 :     adfGeoTransform[0] = 0.0;
      77             180 :     adfGeoTransform[1] = 1.0;
      78             180 :     adfGeoTransform[2] = 0.0;
      79             180 :     adfGeoTransform[3] = 0.0;
      80             180 :     adfGeoTransform[4] = 0.0;
      81             180 :     adfGeoTransform[5] = 1.0;
      82             180 : }
      83                 : 
      84                 : /************************************************************************/
      85                 : /*                          ~GDALJP2Metadata()                          */
      86                 : /************************************************************************/
      87                 : 
      88             180 : GDALJP2Metadata::~GDALJP2Metadata()
      89                 : 
      90                 : {
      91             180 :     CPLFree( pszProjection );
      92             180 :     if( nGCPCount > 0 )
      93                 :     {
      94               7 :         GDALDeinitGCPs( nGCPCount, pasGCPList );
      95               7 :         CPLFree( pasGCPList );
      96                 :     }
      97                 : 
      98             180 :     CPLFree( pabyGeoTIFFData );
      99             180 :     CPLFree( pabyMSIGData );
     100             180 :     CSLDestroy( papszGMLMetadata );
     101             180 :     CSLDestroy( papszMetadata );
     102             180 :     CPLFree( pszXMPMetadata );
     103             180 : }
     104                 : 
     105                 : /************************************************************************/
     106                 : /*                            ReadAndParse()                            */
     107                 : /*                                                                      */
     108                 : /*      Read a JP2 file and try to collect georeferencing               */
     109                 : /*      information from the various available forms.  Returns TRUE     */
     110                 : /*      if anything useful is found.                                    */
     111                 : /************************************************************************/
     112                 : 
     113             143 : int GDALJP2Metadata::ReadAndParse( const char *pszFilename )
     114                 : 
     115                 : {
     116                 :     VSILFILE *fpLL;
     117                 :         
     118             143 :     fpLL = VSIFOpenL( pszFilename, "rb" );
     119                 :         
     120             143 :     if( fpLL == NULL )
     121                 :     {
     122                 :         CPLDebug( "GDALJP2Metadata", "Could not even open %s.", 
     123               0 :                   pszFilename );
     124                 : 
     125               0 :         return FALSE;
     126                 :     }
     127                 : 
     128             143 :     ReadBoxes( fpLL );
     129             143 :     VSIFCloseL( fpLL );
     130                 :             
     131                 : /* -------------------------------------------------------------------- */
     132                 : /*      Try JP2GeoTIFF, GML and finally MSIG to get something.          */
     133                 : /* -------------------------------------------------------------------- */
     134             143 :     if( !ParseJP2GeoTIFF() && !ParseGMLCoverageDesc() )
     135              65 :         ParseMSIG();
     136                 : 
     137                 : /* -------------------------------------------------------------------- */
     138                 : /*      If we still don't have a geotransform, look for a world         */
     139                 : /*      file.                                                           */
     140                 : /* -------------------------------------------------------------------- */
     141             143 :     if( !bHaveGeoTransform )
     142                 :     {
     143                 :         bHaveGeoTransform = 
     144                 :             GDALReadWorldFile( pszFilename, NULL, adfGeoTransform )
     145              75 :             || GDALReadWorldFile( pszFilename, ".wld", adfGeoTransform );
     146                 :     }
     147                 : 
     148                 : /* -------------------------------------------------------------------- */
     149                 : /*      Return success either either of projection or geotransform      */
     150                 : /*      or gcps.                                                        */
     151                 : /* -------------------------------------------------------------------- */
     152                 :     return bHaveGeoTransform
     153                 :         || nGCPCount > 0 
     154             143 :         || (pszProjection != NULL && strlen(pszProjection) > 0);
     155                 : }
     156                 : 
     157                 : /************************************************************************/
     158                 : /*                           CollectGMLData()                           */
     159                 : /*                                                                      */
     160                 : /*      Read all the asoc boxes after this node, and store the          */
     161                 : /*      contain xml documents along with the name from the label.       */
     162                 : /************************************************************************/
     163                 : 
     164              27 : void GDALJP2Metadata::CollectGMLData( GDALJP2Box *poGMLData )
     165                 : 
     166                 : {
     167              27 :     GDALJP2Box oChildBox( poGMLData->GetFILE() );
     168                 : 
     169              27 :     oChildBox.ReadFirstChild( poGMLData );
     170                 : 
     171             108 :     while( strlen(oChildBox.GetType()) > 0 )
     172                 :     {
     173              54 :         if( EQUAL(oChildBox.GetType(),"asoc") )
     174                 :         {
     175              27 :             GDALJP2Box oSubChildBox( oChildBox.GetFILE() );
     176                 : 
     177              27 :             char *pszLabel = NULL;
     178              27 :             char *pszXML = NULL;
     179                 : 
     180              27 :             oSubChildBox.ReadFirstChild( &oChildBox );
     181                 :             
     182             108 :             while( strlen(oSubChildBox.GetType()) > 0 )
     183                 :             {
     184              54 :                 if( EQUAL(oSubChildBox.GetType(),"lbl ") )
     185              27 :                     pszLabel = (char *)oSubChildBox.ReadBoxData();
     186              27 :                 else if( EQUAL(oSubChildBox.GetType(),"xml ") )
     187              27 :                     pszXML = (char *) oSubChildBox.ReadBoxData();
     188                 : 
     189              54 :                 oSubChildBox.ReadNextChild( &oChildBox );
     190                 :             }
     191                 :             
     192              27 :             if( pszLabel != NULL && pszXML != NULL )
     193                 :                 papszGMLMetadata = CSLSetNameValue( papszGMLMetadata, 
     194              27 :                                                     pszLabel, pszXML );
     195              27 :             CPLFree( pszLabel );
     196              27 :             CPLFree( pszXML );
     197                 :         }
     198                 :         
     199              54 :         oChildBox.ReadNextChild( poGMLData );
     200              27 :     }
     201              27 : }
     202                 : 
     203                 : /************************************************************************/
     204                 : /*                             ReadBoxes()                              */
     205                 : /************************************************************************/
     206                 : 
     207             143 : int GDALJP2Metadata::ReadBoxes( VSILFILE *fpVSIL )
     208                 : 
     209                 : {
     210             143 :     GDALJP2Box oBox( fpVSIL );
     211             143 :     int iBox = 0;
     212                 : 
     213             143 :     if (!oBox.ReadFirst())
     214               0 :         return FALSE;
     215                 : 
     216             679 :     while( strlen(oBox.GetType()) > 0 )
     217                 :     {
     218                 : #ifdef DEBUG
     219             487 :         if (CSLTestBoolean(CPLGetConfigOption("DUMP_JP2_BOXES", "NO")))
     220               0 :             oBox.DumpReadable(stderr);
     221                 : #endif
     222                 : 
     223                 : /* -------------------------------------------------------------------- */
     224                 : /*      Collect geotiff box.                                            */
     225                 : /* -------------------------------------------------------------------- */
     226             487 :         if( EQUAL(oBox.GetType(),"uuid") 
     227                 :             && memcmp( oBox.GetUUID(), msi_uuid2, 16 ) == 0 )
     228                 :         {
     229              74 :             nGeoTIFFSize = (int) oBox.GetDataLength();
     230              74 :             pabyGeoTIFFData = oBox.ReadBoxData();
     231              74 :             if (pabyGeoTIFFData == NULL)
     232                 :             {
     233               0 :                 CPLDebug("GDALJP2", "Cannot read data for UUID GeoTIFF box");
     234               0 :                 nGeoTIFFSize = 0;
     235                 :             }
     236                 :         }
     237                 : 
     238                 : /* -------------------------------------------------------------------- */
     239                 : /*      Collect MSIG box.                                               */
     240                 : /* -------------------------------------------------------------------- */
     241             487 :         if( EQUAL(oBox.GetType(),"uuid") 
     242                 :             && memcmp( oBox.GetUUID(), msig_uuid, 16 ) == 0 )
     243                 :         {
     244               0 :             nMSIGSize = (int) oBox.GetDataLength();
     245               0 :             pabyMSIGData = oBox.ReadBoxData();
     246                 : 
     247               0 :             if( nMSIGSize < 70
     248                 :                 || pabyMSIGData == NULL
     249                 :                 || memcmp( pabyMSIGData, "MSIG/", 5 ) != 0 )
     250                 :             {
     251               0 :                 CPLFree( pabyMSIGData );
     252               0 :                 pabyMSIGData = NULL;
     253               0 :                 nMSIGSize = 0;
     254                 :             }
     255                 :         }
     256                 : 
     257                 : /* -------------------------------------------------------------------- */
     258                 : /*      Collect XMP box.                                                */
     259                 : /* -------------------------------------------------------------------- */
     260             487 :         if( EQUAL(oBox.GetType(),"uuid")
     261                 :             && memcmp( oBox.GetUUID(), xmp_uuid, 16 ) == 0 &&
     262                 :             pszXMPMetadata == NULL )
     263                 :         {
     264               4 :             pszXMPMetadata = (char*) oBox.ReadBoxData();
     265                 :         }
     266                 : 
     267                 : /* -------------------------------------------------------------------- */
     268                 : /*      Process asoc box looking for Labelled GML data.                 */
     269                 : /* -------------------------------------------------------------------- */
     270             487 :         if( EQUAL(oBox.GetType(),"asoc") )
     271                 :         {
     272              27 :             GDALJP2Box oSubBox( fpVSIL );
     273                 : 
     274              27 :             oSubBox.ReadFirstChild( &oBox );
     275              27 :             if( EQUAL(oSubBox.GetType(),"lbl ") )
     276                 :             {
     277              27 :                 char *pszLabel = (char *) oSubBox.ReadBoxData();
     278              27 :                 if( pszLabel != NULL && EQUAL(pszLabel,"gml.data") )
     279                 :                 {
     280              27 :                     CollectGMLData( &oBox );
     281                 :                 }
     282              27 :                 CPLFree( pszLabel );
     283              27 :             }
     284                 :         }
     285                 : 
     286                 : /* -------------------------------------------------------------------- */
     287                 : /*      Process simple xml boxes.                                       */
     288                 : /* -------------------------------------------------------------------- */
     289             487 :         if( EQUAL(oBox.GetType(),"xml ") )
     290                 :         {
     291               6 :             CPLString osBoxName;
     292               6 :             char *pszXML = (char *) oBox.ReadBoxData();
     293                 : 
     294               6 :             osBoxName.Printf( "BOX_%d", iBox++ );
     295                 :             
     296                 :             papszGMLMetadata = CSLSetNameValue( papszGMLMetadata, 
     297               6 :                                                 osBoxName, pszXML );
     298               6 :             CPLFree( pszXML );
     299                 :         }
     300                 : 
     301                 : /* -------------------------------------------------------------------- */
     302                 : /*      Check for a resd box in jp2h.                                   */
     303                 : /* -------------------------------------------------------------------- */
     304             487 :         if( EQUAL(oBox.GetType(),"jp2h") )
     305                 :         {
     306              94 :             GDALJP2Box oSubBox( fpVSIL );
     307                 : 
     308             327 :             for( oSubBox.ReadFirstChild( &oBox );
     309                 :                  strlen(oSubBox.GetType()) > 0;
     310                 :                  oSubBox.ReadNextChild( &oBox ) )
     311                 :             {
     312             233 :                 if( EQUAL(oSubBox.GetType(),"res ") )
     313                 :                 {
     314               4 :                     GDALJP2Box oResBox( fpVSIL );
     315                 : 
     316               4 :                     oResBox.ReadFirstChild( &oSubBox );
     317                 :                     
     318                 :                     // we will use either the resd or resc box, which ever
     319                 :                     // happens to be first.  Should we prefer resd?
     320               4 :                     unsigned char *pabyResData = NULL;
     321               4 :                     if( oResBox.GetDataLength() == 10 &&
     322                 :                         (pabyResData = oResBox.ReadBoxData()) != NULL )
     323                 :                     {
     324                 :                         int nVertNum, nVertDen, nVertExp;
     325                 :                         int nHorzNum, nHorzDen, nHorzExp;
     326                 :                         
     327               4 :                         nVertNum = pabyResData[0] * 256 + pabyResData[1];
     328               4 :                         nVertDen = pabyResData[2] * 256 + pabyResData[3];
     329               4 :                         nHorzNum = pabyResData[4] * 256 + pabyResData[5];
     330               4 :                         nHorzDen = pabyResData[6] * 256 + pabyResData[7];
     331               4 :                         nVertExp = pabyResData[8];
     332               4 :                         nHorzExp = pabyResData[9];
     333                 :                         
     334                 :                         // compute in pixels/cm 
     335                 :                         double dfVertRes = 
     336               4 :                             (nVertNum/(double)nVertDen) * pow(10.0,nVertExp)/100;
     337                 :                         double dfHorzRes = 
     338               4 :                             (nHorzNum/(double)nHorzDen) * pow(10.0,nHorzExp)/100;
     339               4 :                         CPLString osFormatter;
     340                 : 
     341                 :                         papszMetadata = CSLSetNameValue( 
     342                 :                             papszMetadata, 
     343                 :                             "TIFFTAG_XRESOLUTION",
     344               4 :                             osFormatter.Printf("%g",dfHorzRes) );
     345                 :                         
     346                 :                         papszMetadata = CSLSetNameValue( 
     347                 :                             papszMetadata, 
     348                 :                             "TIFFTAG_YRESOLUTION",
     349               4 :                             osFormatter.Printf("%g",dfVertRes) );
     350                 :                         papszMetadata = CSLSetNameValue( 
     351                 :                             papszMetadata, 
     352                 :                             "TIFFTAG_RESOLUTIONUNIT", 
     353               4 :                             "3 (pixels/cm)" );
     354                 :                         
     355               4 :                         CPLFree( pabyResData );
     356               4 :                     }
     357                 :                 }
     358              94 :             }
     359                 :         }
     360                 : 
     361             487 :         if (!oBox.ReadNext())
     362              94 :             break;
     363                 :     }
     364                 : 
     365             143 :     return TRUE;
     366                 : }
     367                 : 
     368                 : /************************************************************************/
     369                 : /*                          ParseJP2GeoTIFF()                           */
     370                 : /************************************************************************/
     371                 : 
     372             143 : int GDALJP2Metadata::ParseJP2GeoTIFF()
     373                 : 
     374                 : {
     375             143 :     if( nGeoTIFFSize < 1 )
     376              69 :         return FALSE;
     377                 : 
     378                 : /* -------------------------------------------------------------------- */
     379                 : /*      Convert raw data into projection and geotransform.              */
     380                 : /* -------------------------------------------------------------------- */
     381              74 :     int bSuccess = TRUE;
     382                 : 
     383              74 :     if( GTIFWktFromMemBuf( nGeoTIFFSize, pabyGeoTIFFData,
     384                 :                            &pszProjection, adfGeoTransform,
     385                 :                            &nGCPCount, &pasGCPList ) != CE_None )
     386                 :     {
     387               0 :         bSuccess = FALSE;
     388                 :     }
     389                 : 
     390              74 :     if( pszProjection == NULL || strlen(pszProjection) == 0 )
     391               0 :         bSuccess = FALSE;
     392                 : 
     393              74 :     if( bSuccess )
     394                 :         CPLDebug( "GDALJP2Metadata", 
     395                 :                   "Got projection from GeoJP2 (geotiff) box: %s", 
     396              74 :                  pszProjection );
     397                 : 
     398             124 :     if( adfGeoTransform[0] != 0 
     399              10 :         || adfGeoTransform[1] != 1 
     400              10 :         || adfGeoTransform[2] != 0
     401              10 :         || adfGeoTransform[3] != 0 
     402              10 :         || adfGeoTransform[4] != 0
     403              10 :         || adfGeoTransform[5] != 1 )
     404              64 :         bHaveGeoTransform = TRUE;
     405                 : 
     406              74 :     return bSuccess;;
     407                 : }
     408                 : 
     409                 : /************************************************************************/
     410                 : /*                             ParseMSIG()                              */
     411                 : /************************************************************************/
     412                 : 
     413              65 : int GDALJP2Metadata::ParseMSIG()
     414                 : 
     415                 : {
     416              65 :     if( nMSIGSize < 70 )
     417              65 :         return FALSE;
     418                 : 
     419                 : /* -------------------------------------------------------------------- */
     420                 : /*      Try and extract worldfile parameters and adjust.                */
     421                 : /* -------------------------------------------------------------------- */
     422               0 :     memcpy( adfGeoTransform + 0, pabyMSIGData + 22 + 8 * 4, 8 );
     423               0 :     memcpy( adfGeoTransform + 1, pabyMSIGData + 22 + 8 * 0, 8 );
     424               0 :     memcpy( adfGeoTransform + 2, pabyMSIGData + 22 + 8 * 2, 8 );
     425               0 :     memcpy( adfGeoTransform + 3, pabyMSIGData + 22 + 8 * 5, 8 );
     426               0 :     memcpy( adfGeoTransform + 4, pabyMSIGData + 22 + 8 * 1, 8 );
     427               0 :     memcpy( adfGeoTransform + 5, pabyMSIGData + 22 + 8 * 3, 8 );
     428                 : 
     429                 :     // data is in LSB (little endian) order in file.
     430                 :     CPL_LSBPTR64( adfGeoTransform + 0 );
     431                 :     CPL_LSBPTR64( adfGeoTransform + 1 );
     432                 :     CPL_LSBPTR64( adfGeoTransform + 2 );
     433                 :     CPL_LSBPTR64( adfGeoTransform + 3 );
     434                 :     CPL_LSBPTR64( adfGeoTransform + 4 );
     435                 :     CPL_LSBPTR64( adfGeoTransform + 5 );
     436                 : 
     437                 :     // correct for center of pixel vs. top left of pixel
     438               0 :     adfGeoTransform[0] -= 0.5 * adfGeoTransform[1];
     439               0 :     adfGeoTransform[0] -= 0.5 * adfGeoTransform[2];
     440               0 :     adfGeoTransform[3] -= 0.5 * adfGeoTransform[4];
     441               0 :     adfGeoTransform[3] -= 0.5 * adfGeoTransform[5];
     442                 : 
     443               0 :     bHaveGeoTransform = TRUE;
     444                 : 
     445               0 :     return TRUE;
     446                 : }
     447                 : 
     448                 : /************************************************************************/
     449                 : /*                         GetDictionaryItem()                          */
     450                 : /************************************************************************/
     451                 : 
     452                 : static CPLXMLNode *
     453               0 : GetDictionaryItem( char **papszGMLMetadata, const char *pszURN )
     454                 : 
     455                 : {
     456                 :     char *pszLabel;
     457               0 :     const char *pszFragmentId = NULL;
     458                 :     int i;
     459                 : 
     460                 : 
     461               0 :     if( EQUALN(pszURN,"urn:jp2k:xml:", 13) )
     462               0 :         pszLabel = CPLStrdup( pszURN + 13 );
     463               0 :     else if( EQUALN(pszURN,"urn:ogc:tc:gmljp2:xml:", 22) )
     464               0 :         pszLabel = CPLStrdup( pszURN + 22 );
     465               0 :     else if( EQUALN(pszURN,"gmljp2://xml/",13) )
     466               0 :         pszLabel = CPLStrdup( pszURN + 13 );
     467                 :     else
     468               0 :         pszLabel = CPLStrdup( pszURN );
     469                 : 
     470                 : /* -------------------------------------------------------------------- */
     471                 : /*      Split out label and fragment id.                                */
     472                 : /* -------------------------------------------------------------------- */
     473               0 :     for( i = 0; pszLabel[i] != '#'; i++ )
     474                 :     {
     475               0 :         if( pszLabel[i] == '\0' )
     476               0 :             return NULL;
     477                 :     }
     478                 : 
     479               0 :     pszFragmentId = pszLabel + i + 1;
     480               0 :     pszLabel[i] = '\0';
     481                 : 
     482                 : /* -------------------------------------------------------------------- */
     483                 : /*      Can we find an XML box with the desired label?                  */
     484                 : /* -------------------------------------------------------------------- */
     485                 :     const char *pszDictionary = 
     486               0 :         CSLFetchNameValue( papszGMLMetadata, pszLabel );
     487                 : 
     488               0 :     if( pszDictionary == NULL )
     489               0 :         return NULL;
     490                 : 
     491                 : /* -------------------------------------------------------------------- */
     492                 : /*      Try and parse the dictionary.                                   */
     493                 : /* -------------------------------------------------------------------- */
     494               0 :     CPLXMLNode *psDictTree = CPLParseXMLString( pszDictionary );
     495                 : 
     496               0 :     if( psDictTree == NULL )
     497                 :     {
     498               0 :         CPLDestroyXMLNode( psDictTree );
     499               0 :         return NULL;
     500                 :     }
     501                 : 
     502               0 :     CPLStripXMLNamespace( psDictTree, NULL, TRUE );
     503                 : 
     504               0 :     CPLXMLNode *psDictRoot = CPLSearchXMLNode( psDictTree, "=Dictionary" );
     505                 :     
     506               0 :     if( psDictRoot == NULL )
     507                 :     {
     508               0 :         CPLDestroyXMLNode( psDictTree );
     509               0 :         return NULL;
     510                 :     }
     511                 : 
     512                 : /* -------------------------------------------------------------------- */
     513                 : /*      Search for matching id.                                         */
     514                 : /* -------------------------------------------------------------------- */
     515               0 :     CPLXMLNode *psEntry, *psHit = NULL;
     516               0 :     for( psEntry = psDictRoot->psChild; 
     517                 :          psEntry != NULL && psHit == NULL; 
     518                 :          psEntry = psEntry->psNext )
     519                 :     {
     520                 :         const char *pszId;
     521                 : 
     522               0 :         if( psEntry->eType != CXT_Element )
     523               0 :             continue;
     524                 : 
     525               0 :         if( !EQUAL(psEntry->pszValue,"dictionaryEntry") )
     526               0 :             continue;
     527                 :         
     528               0 :         if( psEntry->psChild == NULL )
     529               0 :             continue;
     530                 : 
     531               0 :         pszId = CPLGetXMLValue( psEntry->psChild, "id", "" );
     532                 : 
     533               0 :         if( EQUAL(pszId, pszFragmentId) )
     534               0 :             psHit = CPLCloneXMLTree( psEntry->psChild );
     535                 :     }
     536                 : 
     537                 : /* -------------------------------------------------------------------- */
     538                 : /*      Cleanup                                                         */
     539                 : /* -------------------------------------------------------------------- */
     540               0 :     CPLFree( pszLabel );
     541               0 :     CPLDestroyXMLNode( psDictTree );
     542                 : 
     543               0 :     return psHit;
     544                 : }
     545                 : 
     546                 :         
     547                 : /************************************************************************/
     548                 : /*                            GMLSRSLookup()                            */
     549                 : /*                                                                      */
     550                 : /*      Lookup an SRS in a dictionary inside this file.  We will get    */
     551                 : /*      something like:                                                 */
     552                 : /*        urn:jp2k:xml:CRSDictionary.xml#crs1112                        */
     553                 : /*                                                                      */
     554                 : /*      We need to split the filename from the fragment id, and         */
     555                 : /*      lookup the fragment in the file if we can find it our           */
     556                 : /*      list of labelled xml boxes.                                     */
     557                 : /************************************************************************/
     558                 : 
     559               0 : int GDALJP2Metadata::GMLSRSLookup( const char *pszURN )
     560                 : 
     561                 : {
     562               0 :     CPLXMLNode *psDictEntry = GetDictionaryItem( papszGMLMetadata, pszURN );
     563                 : 
     564               0 :     if( psDictEntry == NULL )
     565               0 :         return FALSE;
     566                 : 
     567                 : /* -------------------------------------------------------------------- */
     568                 : /*      Reserialize this fragment.                                      */
     569                 : /* -------------------------------------------------------------------- */
     570               0 :     char *pszDictEntryXML = CPLSerializeXMLTree( psDictEntry );
     571               0 :     CPLDestroyXMLNode( psDictEntry );
     572                 : 
     573                 : /* -------------------------------------------------------------------- */
     574                 : /*      Try to convert into an OGRSpatialReference.                     */
     575                 : /* -------------------------------------------------------------------- */
     576               0 :     OGRSpatialReference oSRS;
     577               0 :     int bSuccess = FALSE;
     578                 : 
     579               0 :     if( oSRS.importFromXML( pszDictEntryXML ) == OGRERR_NONE )
     580                 :     {
     581               0 :         CPLFree( pszProjection );
     582               0 :         pszProjection = NULL;
     583                 : 
     584               0 :         oSRS.exportToWkt( &pszProjection );
     585               0 :         bSuccess = TRUE;
     586                 :     }
     587                 : 
     588               0 :     CPLFree( pszDictEntryXML );
     589                 : 
     590               0 :     return bSuccess;
     591                 : }
     592                 : 
     593                 : /************************************************************************/
     594                 : /*                        ParseGMLCoverageDesc()                        */
     595                 : /************************************************************************/
     596                 : 
     597              69 : int GDALJP2Metadata::ParseGMLCoverageDesc() 
     598                 : 
     599                 : {
     600                 : /* -------------------------------------------------------------------- */
     601                 : /*      Do we have an XML doc that is apparently a coverage             */
     602                 : /*      description?                                                    */
     603                 : /* -------------------------------------------------------------------- */
     604                 :     const char *pszCoverage = CSLFetchNameValue( papszGMLMetadata, 
     605              69 :                                                  "gml.root-instance" );
     606                 : 
     607              69 :     if( pszCoverage == NULL )
     608              65 :         return FALSE;
     609                 : 
     610               4 :     CPLDebug( "GDALJP2Metadata", "Found GML Box:\n%s", pszCoverage );
     611                 : 
     612                 : /* -------------------------------------------------------------------- */
     613                 : /*      Try parsing the XML.  Wipe any namespace prefixes.              */
     614                 : /* -------------------------------------------------------------------- */
     615               4 :     CPLXMLNode *psXML = CPLParseXMLString( pszCoverage );
     616                 : 
     617               4 :     if( psXML == NULL )
     618               0 :         return FALSE;
     619                 : 
     620               4 :     CPLStripXMLNamespace( psXML, NULL, TRUE );
     621                 : 
     622                 : /* -------------------------------------------------------------------- */
     623                 : /*      Isolate RectifiedGrid.  Eventually we will need to support      */
     624                 : /*      other georeferencing objects.                                   */
     625                 : /* -------------------------------------------------------------------- */
     626               4 :     CPLXMLNode *psRG = CPLSearchXMLNode( psXML, "=RectifiedGrid" );
     627               4 :     CPLXMLNode *psOriginPoint = NULL;
     628               4 :     const char *pszOffset1=NULL, *pszOffset2=NULL;
     629                 : 
     630               4 :     if( psRG != NULL )
     631                 :     {
     632               4 :         psOriginPoint = CPLGetXMLNode( psRG, "origin.Point" );
     633                 : 
     634                 :         
     635               4 :         CPLXMLNode *psOffset1 = CPLGetXMLNode( psRG, "offsetVector" );
     636               4 :         if( psOffset1 != NULL )
     637                 :         {
     638               4 :             pszOffset1 = CPLGetXMLValue( psOffset1, "", NULL );
     639                 :             pszOffset2 = CPLGetXMLValue( psOffset1->psNext, "=offsetVector", 
     640               4 :                                          NULL );
     641                 :         }
     642                 :     }
     643                 : 
     644                 : /* -------------------------------------------------------------------- */
     645                 : /*      If we are missing any of the origin or 2 offsets then give up.  */
     646                 : /* -------------------------------------------------------------------- */
     647               4 :     if( psOriginPoint == NULL || pszOffset1 == NULL || pszOffset2 == NULL )
     648                 :     {
     649               0 :         CPLDestroyXMLNode( psXML );
     650               0 :         return FALSE;
     651                 :     }
     652                 : 
     653                 : /* -------------------------------------------------------------------- */
     654                 : /*      Extract origin location.                                        */
     655                 : /* -------------------------------------------------------------------- */
     656               4 :     OGRPoint *poOriginGeometry = NULL;
     657               4 :     const char *pszSRSName = NULL;
     658                 : 
     659               4 :     if( psOriginPoint != NULL )
     660                 :     {
     661                 :         poOriginGeometry = (OGRPoint *) 
     662               4 :             OGR_G_CreateFromGMLTree( psOriginPoint );
     663                 : 
     664               8 :         if( poOriginGeometry != NULL 
     665               4 :             && wkbFlatten(poOriginGeometry->getGeometryType()) != wkbPoint )
     666                 :         {
     667               0 :             delete poOriginGeometry;
     668               0 :             poOriginGeometry = NULL;
     669                 :         }
     670                 : 
     671                 :         // SRS?
     672               4 :         pszSRSName = CPLGetXMLValue( psOriginPoint, "srsName", NULL );
     673                 :     }
     674                 : 
     675                 : /* -------------------------------------------------------------------- */
     676                 : /*      Extract offset(s)                                               */
     677                 : /* -------------------------------------------------------------------- */
     678               4 :     char **papszOffset1Tokens = NULL;
     679               4 :     char **papszOffset2Tokens = NULL;
     680               4 :     int bSuccess = FALSE;
     681                 : 
     682                 :     papszOffset1Tokens = 
     683               4 :         CSLTokenizeStringComplex( pszOffset1, " ,", FALSE, FALSE );
     684                 :     papszOffset2Tokens = 
     685               4 :         CSLTokenizeStringComplex( pszOffset2, " ,", FALSE, FALSE );
     686                 : 
     687               4 :     if( CSLCount(papszOffset1Tokens) >= 2
     688                 :         && CSLCount(papszOffset2Tokens) >= 2
     689                 :         && poOriginGeometry != NULL )
     690                 :     {
     691               4 :         adfGeoTransform[0] = poOriginGeometry->getX();
     692               4 :         adfGeoTransform[1] = atof(papszOffset1Tokens[0]);
     693               4 :         adfGeoTransform[2] = atof(papszOffset2Tokens[0]);
     694               4 :         adfGeoTransform[3] = poOriginGeometry->getY();
     695               4 :         adfGeoTransform[4] = atof(papszOffset1Tokens[1]);
     696               4 :         adfGeoTransform[5] = atof(papszOffset2Tokens[1]);
     697                 : 
     698                 :         // offset from center of pixel.
     699               4 :         adfGeoTransform[0] -= adfGeoTransform[1]*0.5;
     700               4 :         adfGeoTransform[0] -= adfGeoTransform[2]*0.5;
     701               4 :         adfGeoTransform[3] -= adfGeoTransform[4]*0.5;
     702               4 :         adfGeoTransform[3] -= adfGeoTransform[5]*0.5;
     703                 : 
     704               4 :         bSuccess = TRUE;
     705               4 :         bHaveGeoTransform = TRUE;
     706                 :     }
     707                 : 
     708               4 :     CSLDestroy( papszOffset1Tokens );
     709               4 :     CSLDestroy( papszOffset2Tokens );
     710                 : 
     711               4 :     if( poOriginGeometry != NULL )
     712               4 :         delete poOriginGeometry;
     713                 : 
     714                 : /* -------------------------------------------------------------------- */
     715                 : /*      If we still don't have an srsName, check for it on the          */
     716                 : /*      boundedBy Envelope.  Some products                              */
     717                 : /*      (ie. EuropeRasterTile23.jpx) use this as the only srsName       */
     718                 : /*      delivery vehicle.                                               */
     719                 : /* -------------------------------------------------------------------- */
     720               4 :     if( pszSRSName == NULL )
     721                 :     {
     722                 :         pszSRSName = 
     723                 :             CPLGetXMLValue( psXML,
     724                 :                             "=FeatureCollection.boundedBy.Envelope.srsName",
     725               4 :                             NULL );
     726                 :     }
     727                 : 
     728                 : /* -------------------------------------------------------------------- */
     729                 : /*      If we have gotten a geotransform, then try to interprete the    */
     730                 : /*      srsName.                                                        */
     731                 : /* -------------------------------------------------------------------- */
     732               4 :     int bNeedAxisFlip = FALSE;
     733                 : 
     734               4 :     if( bSuccess && pszSRSName != NULL 
     735                 :         && (pszProjection == NULL || strlen(pszProjection) == 0) )
     736                 :     {
     737               4 :         OGRSpatialReference oSRS;
     738                 : 
     739               4 :         if( EQUALN(pszSRSName,"epsg:",5) )
     740                 :         {
     741               0 :             if( oSRS.SetFromUserInput( pszSRSName ) == OGRERR_NONE )
     742               0 :                 oSRS.exportToWkt( &pszProjection );
     743                 :         }
     744               4 :         else if( EQUALN(pszSRSName,"urn:",4) 
     745                 :                  && strstr(pszSRSName,":def:") != NULL
     746                 :                  && oSRS.importFromURN(pszSRSName) == OGRERR_NONE )
     747                 :         {
     748               4 :             const char *pszCode = strrchr(pszSRSName,':') + 1;
     749                 : 
     750               4 :             oSRS.exportToWkt( &pszProjection );
     751                 : 
     752                 :             // Per #2131
     753               4 :             if( atoi(pszCode) >= 4000 && atoi(pszCode) <= 4999 )
     754                 :             {
     755                 :                 CPLDebug( "GMLJP2", "Request axis flip for SRS=%s",
     756               4 :                           pszSRSName );
     757               4 :                 bNeedAxisFlip = TRUE;
     758                 :             }
     759                 :         }
     760               0 :         else if( !GMLSRSLookup( pszSRSName ) )
     761                 :         {
     762                 :             CPLDebug( "GDALJP2Metadata", 
     763                 :                       "Unable to evaluate SRSName=%s", 
     764               0 :                       pszSRSName );
     765               4 :         }
     766                 :     }
     767                 : 
     768               4 :     if( pszProjection )
     769                 :         CPLDebug( "GDALJP2Metadata", 
     770                 :                   "Got projection from GML box: %s", 
     771               4 :                  pszProjection );
     772                 : 
     773               4 :     CPLDestroyXMLNode( psXML );
     774               4 :     psXML = NULL;
     775                 : 
     776                 : /* -------------------------------------------------------------------- */
     777                 : /*      Do we need to flip the axes?                                    */
     778                 : /* -------------------------------------------------------------------- */
     779               4 :     if( bNeedAxisFlip
     780                 :         && CSLTestBoolean( CPLGetConfigOption( "GDAL_IGNORE_AXIS_ORIENTATION",
     781                 :                                                "FALSE" ) ) )
     782                 :     {
     783               0 :         bNeedAxisFlip = FALSE;
     784               0 :         CPLDebug( "GMLJP2", "Supressed axis flipping based on GDAL_IGNORE_AXIS_ORIENTATION." );
     785                 :     }
     786                 : 
     787               4 :     if( bNeedAxisFlip )
     788                 :     {
     789                 :         double dfTemp;
     790                 : 
     791                 :         CPLDebug( "GMLJP2", 
     792               4 :                   "Flipping axis orientation in GMLJP2 coverage description." );
     793                 : 
     794               4 :         dfTemp = adfGeoTransform[0];
     795               4 :         adfGeoTransform[0] = adfGeoTransform[3];
     796               4 :         adfGeoTransform[3] = dfTemp;
     797                 : 
     798               4 :         int swapWith1Index = 4;
     799               4 :         int swapWith2Index = 5;
     800                 : 
     801               4 :         if( CSLTestBoolean( CPLGetConfigOption( "GDAL_JP2K_ALT_OFFSETVECTOR_ORDER",
     802                 :                                                 "FALSE" ) ) )
     803                 :         {
     804               0 :             swapWith1Index = 5;
     805               0 :             swapWith2Index = 4;
     806                 :             CPLDebug( "GMLJP2", "Choosing alternate GML \"<offsetVector>\" order based on "
     807               0 :                 "GDAL_JP2K_ALT_OFFSETVECTOR_ORDER." );
     808                 :         }
     809                 : 
     810               4 :         dfTemp = adfGeoTransform[1];
     811               4 :         adfGeoTransform[1] = adfGeoTransform[swapWith1Index];
     812               4 :         adfGeoTransform[swapWith1Index] = dfTemp;
     813                 : 
     814               4 :         dfTemp = adfGeoTransform[2];
     815               4 :         adfGeoTransform[2] = adfGeoTransform[swapWith2Index];
     816               4 :         adfGeoTransform[swapWith2Index] = dfTemp;
     817                 :     }
     818                 : 
     819               4 :     return pszProjection != NULL && bSuccess;
     820                 : }
     821                 : 
     822                 : /************************************************************************/
     823                 : /*                           SetProjection()                            */
     824                 : /************************************************************************/
     825                 : 
     826              35 : void GDALJP2Metadata::SetProjection( const char *pszWKT )
     827                 : 
     828                 : {
     829              35 :     CPLFree( pszProjection );
     830              35 :     pszProjection = CPLStrdup(pszWKT);
     831              35 : }
     832                 : 
     833                 : /************************************************************************/
     834                 : /*                              SetGCPs()                               */
     835                 : /************************************************************************/
     836                 : 
     837              24 : void GDALJP2Metadata::SetGCPs( int nCount, const GDAL_GCP *pasGCPsIn )
     838                 : 
     839                 : {
     840              24 :     if( nGCPCount > 0 )
     841                 :     {
     842               0 :         GDALDeinitGCPs( nGCPCount, pasGCPList );
     843               0 :         CPLFree( pasGCPList );
     844                 :     }
     845                 : 
     846              24 :     nGCPCount = nCount;
     847              24 :     pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPsIn);
     848              24 : }
     849                 : 
     850                 : /************************************************************************/
     851                 : /*                          SetGeoTransform()                           */
     852                 : /************************************************************************/
     853                 : 
     854              35 : void GDALJP2Metadata::SetGeoTransform( double *padfGT )
     855                 : 
     856                 : {
     857              35 :     memcpy( adfGeoTransform, padfGT, sizeof(double) * 6 );
     858              35 : }
     859                 : 
     860                 : /************************************************************************/
     861                 : /*                          CreateJP2GeoTIFF()                          */
     862                 : /************************************************************************/
     863                 : 
     864              32 : GDALJP2Box *GDALJP2Metadata::CreateJP2GeoTIFF()
     865                 : 
     866                 : {
     867                 : /* -------------------------------------------------------------------- */
     868                 : /*      Prepare the memory buffer containing the degenerate GeoTIFF     */
     869                 : /*      file.                                                           */
     870                 : /* -------------------------------------------------------------------- */
     871              32 :     int         nGTBufSize = 0;
     872              32 :     unsigned char *pabyGTBuf = NULL;
     873                 : 
     874              32 :     if( GTIFMemBufFromWkt( pszProjection, adfGeoTransform, 
     875                 :                            nGCPCount, pasGCPList,
     876                 :                            &nGTBufSize, &pabyGTBuf ) != CE_None )
     877               0 :         return NULL;
     878                 : 
     879              32 :     if( nGTBufSize == 0 )
     880               0 :         return NULL;
     881                 : 
     882                 : /* -------------------------------------------------------------------- */
     883                 : /*      Write to a box on the JP2 file.                                 */
     884                 : /* -------------------------------------------------------------------- */
     885                 :     GDALJP2Box *poBox;
     886                 : 
     887              32 :     poBox = GDALJP2Box::CreateUUIDBox( msi_uuid2, nGTBufSize, pabyGTBuf );
     888                 :     
     889              32 :     CPLFree( pabyGTBuf );
     890                 : 
     891              32 :     return poBox;
     892                 : }
     893                 : 
     894                 : /************************************************************************/
     895                 : /*                         PrepareCoverageBox()                         */
     896                 : /************************************************************************/
     897                 : 
     898              23 : GDALJP2Box *GDALJP2Metadata::CreateGMLJP2( int nXSize, int nYSize )
     899                 : 
     900                 : {
     901                 : /* -------------------------------------------------------------------- */
     902                 : /*      This is a backdoor to let us embed a literal gmljp2 chunk       */
     903                 : /*      supplied by the user as an external file.  This is mostly       */
     904                 : /*      for preparing test files with exotic contents.                  */
     905                 : /* -------------------------------------------------------------------- */
     906              23 :     if( CPLGetConfigOption( "GMLJP2OVERRIDE", NULL ) != NULL )
     907                 :     {
     908               0 :         VSILFILE *fp = VSIFOpenL( CPLGetConfigOption( "GMLJP2OVERRIDE",""), "r" );
     909               0 :         char *pszGML = NULL;
     910                 : 
     911               0 :         if( fp == NULL )
     912                 :         {
     913                 :             CPLError( CE_Failure, CPLE_AppDefined, 
     914               0 :                       "Unable to open GMLJP2OVERRIDE file." );
     915               0 :             return NULL;
     916                 :         }
     917                 :         
     918               0 :         VSIFSeekL( fp, 0, SEEK_END );
     919               0 :         int nLength = (int) VSIFTellL( fp );
     920               0 :         pszGML = (char *) CPLCalloc(1,nLength+1);
     921               0 :         VSIFSeekL( fp, 0, SEEK_SET );
     922               0 :         VSIFReadL( pszGML, 1, nLength, fp );
     923               0 :         VSIFCloseL( fp );
     924                 : 
     925                 :         GDALJP2Box *apoGMLBoxes[2];
     926                 : 
     927               0 :         apoGMLBoxes[0] = GDALJP2Box::CreateLblBox( "gml.data" );
     928                 :         apoGMLBoxes[1] = 
     929                 :             GDALJP2Box::CreateLabelledXMLAssoc( "gml.root-instance", 
     930               0 :                                                 pszGML );
     931                 : 
     932               0 :         GDALJP2Box *poGMLData = GDALJP2Box::CreateAsocBox( 2, apoGMLBoxes);
     933                 :         
     934               0 :         delete apoGMLBoxes[0];
     935               0 :         delete apoGMLBoxes[1];
     936                 : 
     937               0 :         CPLFree( pszGML );
     938                 :         
     939               0 :         return poGMLData;
     940                 :     }
     941                 : 
     942                 : /* -------------------------------------------------------------------- */
     943                 : /*      Try do determine a PCS or GCS code we can use.                  */
     944                 : /* -------------------------------------------------------------------- */
     945              23 :     OGRSpatialReference oSRS;
     946              23 :     char *pszWKTCopy = (char *) pszProjection;
     947              23 :     int nEPSGCode = 0;
     948                 :     char szSRSName[100];
     949              23 :     int  bNeedAxisFlip = FALSE;
     950                 : 
     951              23 :     if( oSRS.importFromWkt( &pszWKTCopy ) != OGRERR_NONE )
     952               2 :         return NULL;
     953                 : 
     954              21 :     if( oSRS.IsProjected() )
     955                 :     {
     956               5 :         const char *pszAuthName = oSRS.GetAuthorityName( "PROJCS" );
     957                 : 
     958               5 :         if( pszAuthName != NULL && EQUAL(pszAuthName,"epsg") )
     959                 :         {
     960               5 :             nEPSGCode = atoi(oSRS.GetAuthorityCode( "PROJCS" ));
     961                 :         }
     962                 :     }
     963              16 :     else if( oSRS.IsGeographic() )
     964                 :     {
     965              16 :         const char *pszAuthName = oSRS.GetAuthorityName( "GEOGCS" );
     966                 : 
     967              16 :         if( pszAuthName != NULL && EQUAL(pszAuthName,"epsg") )
     968                 :         {
     969              12 :             nEPSGCode = atoi(oSRS.GetAuthorityCode( "GEOGCS" ));
     970              12 :             bNeedAxisFlip = TRUE;
     971                 :         }
     972                 :     }
     973                 : 
     974              21 :     if( nEPSGCode != 0 )
     975              17 :         sprintf( szSRSName, "urn:ogc:def:crs:EPSG::%d", nEPSGCode );
     976                 :     else
     977                 :         strcpy( szSRSName, 
     978               4 :                 "gmljp2://xml/CRSDictionary.gml#ogrcrs1" );
     979                 : 
     980                 : /* -------------------------------------------------------------------- */
     981                 : /*      Prepare coverage origin and offset vectors.  Take axis          */
     982                 : /*      order into account if needed.                                   */
     983                 : /* -------------------------------------------------------------------- */
     984                 :     double adfOrigin[2];
     985                 :     double adfXVector[2];
     986                 :     double adfYVector[2];
     987                 :     
     988              21 :     adfOrigin[0] = adfGeoTransform[0] + adfGeoTransform[1] * 0.5
     989              21 :         + adfGeoTransform[4] * 0.5;
     990              21 :     adfOrigin[1] = adfGeoTransform[3] + adfGeoTransform[2] * 0.5
     991              21 :         + adfGeoTransform[5] * 0.5;
     992              21 :     adfXVector[0] = adfGeoTransform[1];
     993              21 :     adfXVector[1] = adfGeoTransform[2];
     994                 :         
     995              21 :     adfYVector[0] = adfGeoTransform[4];
     996              21 :     adfYVector[1] = adfGeoTransform[5];
     997                 :     
     998              21 :     if( bNeedAxisFlip
     999                 :         && CSLTestBoolean( CPLGetConfigOption( "GDAL_IGNORE_AXIS_ORIENTATION",
    1000                 :                                                "FALSE" ) ) )
    1001                 :     {
    1002               0 :         bNeedAxisFlip = FALSE;
    1003               0 :         CPLDebug( "GMLJP2", "Supressed axis flipping on write based on GDAL_IGNORE_AXIS_ORIENTATION." );
    1004                 :     }
    1005                 : 
    1006              21 :     if( bNeedAxisFlip )
    1007                 :     {
    1008                 :         double dfTemp;
    1009                 :         
    1010              12 :         CPLDebug( "GMLJP2", "Flipping GML coverage axis order." );
    1011                 :         
    1012              12 :         dfTemp = adfOrigin[0];
    1013              12 :         adfOrigin[0] = adfOrigin[1];
    1014              12 :         adfOrigin[1] = dfTemp;
    1015                 : 
    1016              12 :         if( CSLTestBoolean( CPLGetConfigOption( "GDAL_JP2K_ALT_OFFSETVECTOR_ORDER",
    1017                 :                                                 "FALSE" ) ) )
    1018                 :         {
    1019                 :             CPLDebug( "GMLJP2", "Choosing alternate GML \"<offsetVector>\" order based on "
    1020               0 :                 "GDAL_JP2K_ALT_OFFSETVECTOR_ORDER." );
    1021                 : 
    1022                 :             /* In this case the swapping is done in an "X" pattern */
    1023               0 :             dfTemp = adfXVector[0];
    1024               0 :             adfXVector[0] = adfYVector[1];
    1025               0 :             adfYVector[1] = dfTemp;
    1026                 : 
    1027               0 :             dfTemp = adfYVector[0];
    1028               0 :             adfYVector[0] = adfXVector[1];
    1029               0 :             adfXVector[1] = dfTemp;
    1030                 :         }
    1031                 :         else
    1032                 :         {
    1033              12 :         dfTemp = adfXVector[0];
    1034              12 :         adfXVector[0] = adfXVector[1];
    1035              12 :         adfXVector[1] = dfTemp;
    1036                 : 
    1037              12 :         dfTemp = adfYVector[0];
    1038              12 :         adfYVector[0] = adfYVector[1];
    1039              12 :         adfYVector[1] = dfTemp;
    1040                 :         }
    1041                 :     }
    1042                 : 
    1043                 : /* -------------------------------------------------------------------- */
    1044                 : /*      For now we hardcode for a minimal instance format.              */
    1045                 : /* -------------------------------------------------------------------- */
    1046              21 :     CPLString osDoc;
    1047                 : 
    1048                 :     osDoc.Printf( 
    1049                 : "<gml:FeatureCollection\n"
    1050                 : "   xmlns:gml=\"http://www.opengis.net/gml\"\n"
    1051                 : "   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
    1052                 : "   xsi:schemaLocation=\"http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlJP2Profile/1.0.0/gmlJP2Profile.xsd\">\n"
    1053                 : "  <gml:boundedBy>\n"
    1054                 : "    <gml:Null>withheld</gml:Null>\n"
    1055                 : "  </gml:boundedBy>\n"
    1056                 : "  <gml:featureMember>\n"
    1057                 : "    <gml:FeatureCollection>\n"
    1058                 : "      <gml:featureMember>\n"
    1059                 : "        <gml:RectifiedGridCoverage dimension=\"2\" gml:id=\"RGC0001\">\n"
    1060                 : "          <gml:rectifiedGridDomain>\n"
    1061                 : "            <gml:RectifiedGrid dimension=\"2\">\n"
    1062                 : "              <gml:limits>\n"
    1063                 : "                <gml:GridEnvelope>\n"
    1064                 : "                  <gml:low>0 0</gml:low>\n"
    1065                 : "                  <gml:high>%d %d</gml:high>\n"
    1066                 : "                </gml:GridEnvelope>\n"
    1067                 : "              </gml:limits>\n"
    1068                 : "              <gml:axisName>x</gml:axisName>\n"
    1069                 : "              <gml:axisName>y</gml:axisName>\n"
    1070                 : "              <gml:origin>\n"
    1071                 : "                <gml:Point gml:id=\"P0001\" srsName=\"%s\">\n"
    1072                 : "                  <gml:pos>%.15g %.15g</gml:pos>\n"
    1073                 : "                </gml:Point>\n"
    1074                 : "              </gml:origin>\n"
    1075                 : "              <gml:offsetVector srsName=\"%s\">%.15g %.15g</gml:offsetVector>\n"
    1076                 : "              <gml:offsetVector srsName=\"%s\">%.15g %.15g</gml:offsetVector>\n"
    1077                 : "            </gml:RectifiedGrid>\n"
    1078                 : "          </gml:rectifiedGridDomain>\n"
    1079                 : "          <gml:rangeSet>\n"
    1080                 : "            <gml:File>\n"
    1081                 : "              <gml:fileName>gmljp2://codestream/0</gml:fileName>\n"
    1082                 : "              <gml:fileStructure>Record Interleaved</gml:fileStructure>\n"
    1083                 : "            </gml:File>\n"
    1084                 : "          </gml:rangeSet>\n"
    1085                 : "        </gml:RectifiedGridCoverage>\n"
    1086                 : "      </gml:featureMember>\n"
    1087                 : "    </gml:FeatureCollection>\n"
    1088                 : "  </gml:featureMember>\n"
    1089                 : "</gml:FeatureCollection>\n",
    1090                 :              nXSize-1, nYSize-1, szSRSName, adfOrigin[0], adfOrigin[1],
    1091                 :              szSRSName, adfXVector[0], adfXVector[1], 
    1092              21 :              szSRSName, adfYVector[0], adfYVector[1] );
    1093                 : 
    1094                 : /* -------------------------------------------------------------------- */
    1095                 : /*      If we need a user defined CRSDictionary entry, prepare it       */
    1096                 : /*      here.                                                           */
    1097                 : /* -------------------------------------------------------------------- */
    1098              21 :     CPLString osDictBox;
    1099                 : 
    1100              21 :     if( nEPSGCode == 0 )
    1101                 :     {
    1102               4 :         char *pszGMLDef = NULL;
    1103                 : 
    1104               4 :         if( oSRS.exportToXML( &pszGMLDef, NULL ) == OGRERR_NONE )
    1105                 :         {
    1106                 :             osDictBox.Printf(  
    1107                 : "<gml:Dictionary gml:id=\"CRSU1\" \n"
    1108                 : "        xmlns:gml=\"http://www.opengis.net/gml\"\n"
    1109                 : "        xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
    1110                 : "        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
    1111                 : "  <gml:dictionaryEntry>\n"
    1112                 : "%s\n"
    1113                 : "  </gml:dictionaryEntry>\n"
    1114                 : "</gml:Dictionary>\n",
    1115               4 :                      pszGMLDef );
    1116                 :         }
    1117               4 :         CPLFree( pszGMLDef );
    1118                 :     }
    1119                 : 
    1120                 : /* -------------------------------------------------------------------- */
    1121                 : /*      Setup the gml.data label.                                       */
    1122                 : /* -------------------------------------------------------------------- */
    1123                 :     GDALJP2Box *apoGMLBoxes[5];
    1124              21 :     int nGMLBoxes = 0;
    1125                 : 
    1126              21 :     apoGMLBoxes[nGMLBoxes++] = GDALJP2Box::CreateLblBox( "gml.data" );
    1127                 : 
    1128                 : /* -------------------------------------------------------------------- */
    1129                 : /*      Setup gml.root-instance.                                        */
    1130                 : /* -------------------------------------------------------------------- */
    1131              42 :     apoGMLBoxes[nGMLBoxes++] = 
    1132              21 :         GDALJP2Box::CreateLabelledXMLAssoc( "gml.root-instance", osDoc );
    1133                 : 
    1134                 : /* -------------------------------------------------------------------- */
    1135                 : /*      Add optional dictionary.                                        */
    1136                 : /* -------------------------------------------------------------------- */
    1137              21 :     if( strlen(osDictBox) > 0 )
    1138               8 :         apoGMLBoxes[nGMLBoxes++] = 
    1139                 :             GDALJP2Box::CreateLabelledXMLAssoc( "CRSDictionary.gml",
    1140               4 :                                                 osDictBox );
    1141                 :         
    1142                 : /* -------------------------------------------------------------------- */
    1143                 : /*      Bundle gml.data boxes into an association.                      */
    1144                 : /* -------------------------------------------------------------------- */
    1145              21 :     GDALJP2Box *poGMLData = GDALJP2Box::CreateAsocBox( nGMLBoxes, apoGMLBoxes);
    1146                 : 
    1147                 : /* -------------------------------------------------------------------- */
    1148                 : /*      Cleanup working boxes.                                          */
    1149                 : /* -------------------------------------------------------------------- */
    1150              88 :     while( nGMLBoxes > 0 )
    1151              46 :         delete apoGMLBoxes[--nGMLBoxes];
    1152                 : 
    1153              21 :     return poGMLData;
    1154                 : }
    1155                 : 
    1156                 : 

Generated by: LCOV version 1.7