LCOV - code coverage report
Current view: directory - gcore - gdalexif.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 184 94 51.1 %
Date: 2012-12-26 Functions: 2 2 100.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: gdalexif.cpp 24551 2012-06-09 20:19:04Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL
       5                 :  * Purpose:  Implements a EXIF directory reader
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2000, Frank Warmerdam
      10                 :  *
      11                 :  * Portions Copyright (c) Her majesty the Queen in right of Canada as
      12                 :  * represented by the Minister of National Defence, 2006.
      13                 :  *
      14                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      15                 :  * copy of this software and associated documentation files (the "Software"),
      16                 :  * to deal in the Software without restriction, including without limitation
      17                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      18                 :  * and/or sell copies of the Software, and to permit persons to whom the
      19                 :  * Software is furnished to do so, subject to the following conditions:
      20                 :  *
      21                 :  * The above copyright notice and this permission notice shall be included
      22                 :  * in all copies or substantial portions of the Software.
      23                 :  *
      24                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      25                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      26                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      27                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      28                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      29                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      30                 :  * DEALINGS IN THE SOFTWARE.
      31                 :  ****************************************************************************/
      32                 : 
      33                 : #include "cpl_conv.h"
      34                 : #include "cpl_port.h"
      35                 : #include "cpl_error.h"
      36                 : #include "cpl_string.h"
      37                 : #include "cpl_vsi.h"
      38                 : 
      39                 : #include "gdalexif.h"
      40                 : 
      41                 : CPL_CVSID("$Id: gdalexif.cpp 24551 2012-06-09 20:19:04Z rouault $");
      42                 : 
      43                 : /************************************************************************/
      44                 : /*                         EXIFPrintData()                              */
      45                 : /************************************************************************/
      46              81 : static void EXIFPrintData(char* pszData, GUInt16 type,
      47                 :                    GUInt32 count, unsigned char* data)
      48                 : {
      49              81 :   const char* sep = "";
      50                 :   char  pszTemp[128];
      51              81 :   char* pszDataEnd = pszData;
      52                 : 
      53              81 :   pszData[0]='\0';
      54                 : 
      55              81 :   switch (type) {
      56                 : 
      57                 :   case TIFF_UNDEFINED:
      58                 :   case TIFF_BYTE:
      59              40 :     for(;count>0;count--) {
      60              32 :       sprintf(pszTemp, "%s%#02x", sep, *data++), sep = " ";
      61              32 :       if (strlen(pszTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
      62               0 :           break;
      63              32 :       strcat(pszDataEnd,pszTemp);
      64              32 :       pszDataEnd += strlen(pszDataEnd);
      65                 :     }
      66               8 :     break;
      67                 : 
      68                 :   case TIFF_SBYTE:
      69               0 :     for(;count>0;count--) {
      70               0 :       sprintf(pszTemp, "%s%d", sep, *(char *)data++), sep = " ";
      71               0 :       if (strlen(pszTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
      72               0 :           break;
      73               0 :       strcat(pszDataEnd,pszTemp);
      74               0 :       pszDataEnd += strlen(pszDataEnd);
      75                 :     }
      76               0 :     break;
      77                 : 
      78                 :   case TIFF_ASCII:
      79              41 :     memcpy( pszData, data, count );
      80              41 :     pszData[count] = '\0';
      81              41 :     break;
      82                 : 
      83                 :   case TIFF_SHORT: {
      84              12 :     register GUInt16 *wp = (GUInt16*)data;
      85              24 :     for(;count>0;count--) {
      86              12 :       sprintf(pszTemp, "%s%u", sep, *wp++), sep = " ";
      87              12 :       if (strlen(pszTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
      88               0 :           break;
      89              12 :       strcat(pszDataEnd,pszTemp);
      90              12 :       pszDataEnd += strlen(pszDataEnd);
      91                 :     }
      92              12 :     break;
      93                 :   }
      94                 :   case TIFF_SSHORT: {
      95               0 :     register GInt16 *wp = (GInt16*)data;
      96               0 :     for(;count>0;count--) {
      97               0 :       sprintf(pszTemp, "%s%d", sep, *wp++), sep = " ";
      98               0 :       strcat(pszData,pszTemp);
      99                 :     }
     100               0 :     break;
     101                 :   }
     102                 :   case TIFF_LONG: {
     103               0 :     register GUInt32 *lp = (GUInt32*)data;
     104               0 :     for(;count>0;count--) {
     105               0 :       sprintf(pszTemp, "%s%lu", sep, (unsigned long) *lp++);
     106               0 :       sep = " ";
     107               0 :       if (strlen(pszTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     108               0 :           break;
     109               0 :       strcat(pszDataEnd,pszTemp);
     110               0 :       pszDataEnd += strlen(pszDataEnd);
     111                 :     }
     112               0 :     break;
     113                 :   }
     114                 :   case TIFF_SLONG: {
     115               0 :     register GInt32 *lp = (GInt32*)data;
     116               0 :     for(;count>0;count--) {
     117               0 :       sprintf(pszTemp, "%s%ld", sep, (long) *lp++), sep = " ";
     118               0 :       if (strlen(pszTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     119               0 :           break;
     120               0 :       strcat(pszDataEnd,pszTemp);
     121               0 :       pszDataEnd += strlen(pszDataEnd);
     122                 :     }
     123               0 :     break;
     124                 :   }
     125                 :   case TIFF_RATIONAL: {
     126              20 :       register GUInt32 *lp = (GUInt32*)data;
     127                 :       //      if(bSwabflag)
     128                 :       //      TIFFSwabArrayOfLong((GUInt32*) data, 2*count);
     129              64 :       for(;count>0;count--) {
     130              44 :       if( (lp[0]==0) && (lp[1] == 0) ) {
     131               0 :           sprintf(pszTemp,"%s(0)",sep);
     132                 :       }
     133                 :       else{
     134                 :           sprintf(pszTemp, "%s(%g)", sep,
     135              44 :               (double) lp[0]/ (double)lp[1]);
     136                 :       }
     137              44 :       sep = " ";
     138              44 :       lp += 2;
     139              44 :       strcat(pszData,pszTemp);
     140                 :       }
     141              20 :       break;
     142                 :   }
     143                 :   case TIFF_SRATIONAL: {
     144               0 :     register GInt32 *lp = (GInt32*)data;
     145               0 :     for(;count>0;count--) {
     146                 :       sprintf(pszTemp, "%s(%g)", sep,
     147               0 :           (float) lp[0]/ (float) lp[1]);
     148               0 :       sep = " ";
     149               0 :       lp += 2;
     150               0 :       if (strlen(pszTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     151               0 :           break;
     152               0 :       strcat(pszDataEnd,pszTemp);
     153               0 :       pszDataEnd += strlen(pszDataEnd);
     154                 :     }
     155               0 :     break;
     156                 :   }
     157                 :   case TIFF_FLOAT: {
     158               0 :     register float *fp = (float *)data;
     159               0 :     for(;count>0;count--) {
     160               0 :       sprintf(pszTemp, "%s%g", sep, *fp++), sep = " ";
     161               0 :       if (strlen(pszTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     162               0 :           break;
     163               0 :       strcat(pszDataEnd,pszTemp);
     164               0 :       pszDataEnd += strlen(pszDataEnd);
     165                 :     }
     166               0 :     break;
     167                 :   }
     168                 :   case TIFF_DOUBLE: {
     169               0 :     register double *dp = (double *)data;
     170               0 :     for(;count>0;count--) {
     171               0 :       sprintf(pszTemp, "%s%g", sep, *dp++), sep = " ";
     172               0 :       if (strlen(pszTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
     173               0 :           break;
     174               0 :       strcat(pszDataEnd,pszTemp);
     175               0 :       pszDataEnd += strlen(pszDataEnd);
     176                 :     }
     177               0 :     break;
     178                 :   }
     179                 : 
     180                 :   default:
     181               0 :     return;
     182                 :   }
     183                 : 
     184              81 :   if (type != TIFF_ASCII && count != 0)
     185                 :   {
     186               0 :       CPLError(CE_Warning, CPLE_AppDefined, "EXIF metadata truncated");
     187                 :   }
     188                 : }
     189                 : 
     190                 : 
     191                 : /************************************************************************/
     192                 : /*                        EXIFExtractMetadata()                         */
     193                 : /*                                                                      */
     194                 : /*      Extract all entry from a IFD                                    */
     195                 : /************************************************************************/
     196              18 : CPLErr EXIFExtractMetadata(char**& papszMetadata,
     197                 :                            void *fpInL, int nOffset,
     198                 :                            int bSwabflag, int nTIFFHEADER,
     199                 :                            int& nExifOffset, int& nInterOffset, int& nGPSOffset)
     200                 : {
     201                 :     GUInt16        nEntryCount;
     202                 :     int space;
     203                 :     unsigned int           n,i;
     204                 :     char          pszTemp[MAXSTRINGLENGTH];
     205                 :     char          pszName[128];
     206                 : 
     207              18 :     VSILFILE* fp = (VSILFILE* )fpInL;
     208                 : 
     209                 :     TIFFDirEntry *poTIFFDirEntry;
     210                 :     TIFFDirEntry *poTIFFDir;
     211                 :     const struct tagname *poExifTags ;
     212              18 :     const struct intr_tag *poInterTags = intr_tags;
     213                 :     const struct gpsname *poGPSTags;
     214                 : 
     215                 : /* -------------------------------------------------------------------- */
     216                 : /*      Read number of entry in directory                               */
     217                 : /* -------------------------------------------------------------------- */
     218              18 :     if( VSIFSeekL(fp, nOffset+nTIFFHEADER, SEEK_SET) != 0
     219                 :         || VSIFReadL(&nEntryCount,1,sizeof(GUInt16),fp) != sizeof(GUInt16) )
     220                 :     {
     221                 :         CPLError( CE_Failure, CPLE_AppDefined,
     222                 :                   "Error reading EXIF Directory count at %d.",
     223               0 :                   nOffset + nTIFFHEADER );
     224               0 :         return CE_Failure;
     225                 :     }
     226                 : 
     227              18 :     if (bSwabflag)
     228               2 :         TIFFSwabShort(&nEntryCount);
     229                 : 
     230                 :     // Some apps write empty directories - see bug 1523.
     231              18 :     if( nEntryCount == 0 )
     232               0 :         return CE_None;
     233                 : 
     234                 :     // Some files are corrupt, a large entry count is a sign of this.
     235              18 :     if( nEntryCount > 125 )
     236                 :     {
     237                 :         CPLError( CE_Warning, CPLE_AppDefined,
     238                 :                   "Ignoring EXIF directory with unlikely entry count (%d).",
     239               1 :                   nEntryCount );
     240               1 :         return CE_Warning;
     241                 :     }
     242                 : 
     243              17 :     poTIFFDir = (TIFFDirEntry *)CPLMalloc(nEntryCount * sizeof(TIFFDirEntry));
     244                 : 
     245                 : /* -------------------------------------------------------------------- */
     246                 : /*      Read all directory entries                                      */
     247                 : /* -------------------------------------------------------------------- */
     248              17 :     n = VSIFReadL(poTIFFDir, 1,nEntryCount*sizeof(TIFFDirEntry),fp);
     249              17 :     if (n != nEntryCount*sizeof(TIFFDirEntry))
     250                 :     {
     251                 :         CPLError( CE_Failure, CPLE_AppDefined,
     252               0 :                   "Could not read all directories");
     253               0 :         return CE_Failure;
     254                 :     }
     255                 : 
     256                 : /* -------------------------------------------------------------------- */
     257                 : /*      Parse all entry information in this directory                   */
     258                 : /* -------------------------------------------------------------------- */
     259             107 :     for(poTIFFDirEntry = poTIFFDir,i=nEntryCount; i > 0; i--,poTIFFDirEntry++) {
     260              90 :         if (bSwabflag) {
     261               2 :             TIFFSwabShort(&poTIFFDirEntry->tdir_tag);
     262               2 :             TIFFSwabShort(&poTIFFDirEntry->tdir_type);
     263               2 :             TIFFSwabLong (&poTIFFDirEntry->tdir_count);
     264               2 :             TIFFSwabLong (&poTIFFDirEntry->tdir_offset);
     265                 :         }
     266                 : 
     267                 : /* -------------------------------------------------------------------- */
     268                 : /*      Find Tag name in table                                          */
     269                 : /* -------------------------------------------------------------------- */
     270              90 :         pszName[0] = '\0';
     271              90 :         pszTemp[0] = '\0';
     272                 : 
     273            5533 :         for (poExifTags = tagnames; poExifTags->tag; poExifTags++)
     274            5494 :             if(poExifTags->tag == poTIFFDirEntry->tdir_tag) {
     275              51 :                 CPLAssert( NULL != poExifTags && NULL != poExifTags->name );
     276                 : 
     277              51 :                 strcpy(pszName, poExifTags->name);
     278              51 :                 break;
     279                 :             }
     280                 : 
     281                 : 
     282              90 :         if( nOffset == nGPSOffset) {
     283              90 :             for( poGPSTags = gpstags; poGPSTags->tag != 0xffff; poGPSTags++ )
     284              90 :                 if( poGPSTags->tag == poTIFFDirEntry->tdir_tag ) {
     285              30 :                     CPLAssert( NULL != poGPSTags && NULL != poGPSTags->name );
     286              30 :                     strcpy(pszName, poGPSTags->name);
     287              30 :                     break;
     288                 :                 }
     289                 :         }
     290                 : /* -------------------------------------------------------------------- */
     291                 : /*      If the tag was not found, look into the interoperability table  */
     292                 : /* -------------------------------------------------------------------- */
     293              90 :         if( nOffset == nInterOffset ) {
     294               0 :             for(poInterTags = intr_tags; poInterTags->tag; poInterTags++)
     295               0 :                 if(poInterTags->tag == poTIFFDirEntry->tdir_tag) {
     296               0 :                     CPLAssert( NULL != poInterTags && NULL != poInterTags->name );
     297               0 :                     strcpy(pszName, poInterTags->name);
     298               0 :                     break;
     299                 :                 }
     300                 :         }
     301                 : 
     302                 : /* -------------------------------------------------------------------- */
     303                 : /*      Save important directory tag offset                             */
     304                 : /* -------------------------------------------------------------------- */
     305              90 :         if( poTIFFDirEntry->tdir_tag == EXIFOFFSETTAG )
     306               5 :             nExifOffset=poTIFFDirEntry->tdir_offset;
     307              90 :         if( poTIFFDirEntry->tdir_tag == INTEROPERABILITYOFFSET )
     308               0 :             nInterOffset=poTIFFDirEntry->tdir_offset;
     309              90 :         if( poTIFFDirEntry->tdir_tag == GPSOFFSETTAG ) {
     310               4 :             nGPSOffset=poTIFFDirEntry->tdir_offset;
     311                 :         }
     312                 : 
     313                 : /* -------------------------------------------------------------------- */
     314                 : /*      If we didn't recognise the tag just ignore it.  To see all      */
     315                 : /*      tags comment out the continue.                                  */
     316                 : /* -------------------------------------------------------------------- */
     317              90 :         if( pszName[0] == '\0' )
     318                 :         {
     319               9 :             sprintf( pszName, "EXIF_%d", poTIFFDirEntry->tdir_tag );
     320               9 :             continue;
     321                 :         }
     322                 : 
     323                 : /* -------------------------------------------------------------------- */
     324                 : /*      For UserComment we need to ignore the language binding and      */
     325                 : /*      just return the actual contents.                                */
     326                 : /* -------------------------------------------------------------------- */
     327              81 :         if( EQUAL(pszName,"EXIF_UserComment")  )
     328                 :         {
     329               0 :             poTIFFDirEntry->tdir_type = TIFF_ASCII;
     330                 : 
     331               0 :             if( poTIFFDirEntry->tdir_count >= 8 )
     332                 :             {
     333               0 :                 poTIFFDirEntry->tdir_count -= 8;
     334               0 :                 poTIFFDirEntry->tdir_offset += 8;
     335                 :             }
     336                 :         }
     337                 : 
     338                 : /* -------------------------------------------------------------------- */
     339                 : /*      Make some UNDEFINED or BYTE fields ASCII for readability.       */
     340                 : /* -------------------------------------------------------------------- */
     341              81 :         if( EQUAL(pszName,"EXIF_ExifVersion")
     342                 :             || EQUAL(pszName,"EXIF_FlashPixVersion")
     343                 :             || EQUAL(pszName,"EXIF_MakerNote")
     344                 :             || EQUAL(pszName,"GPSProcessingMethod") )
     345              10 :             poTIFFDirEntry->tdir_type = TIFF_ASCII;
     346                 : 
     347                 : /* -------------------------------------------------------------------- */
     348                 : /*      Print tags                                                      */
     349                 : /* -------------------------------------------------------------------- */
     350              81 :         int nDataWidth = TIFFDataWidth((TIFFDataType) poTIFFDirEntry->tdir_type);
     351              81 :         space = poTIFFDirEntry->tdir_count * nDataWidth;
     352                 : 
     353                 :         /* Previous multiplication could overflow, hence this additional check */
     354              81 :         if (poTIFFDirEntry->tdir_count > MAXSTRINGLENGTH)
     355                 :         {
     356                 :             CPLError( CE_Warning, CPLE_AppDefined,
     357                 :                       "Too many bytes in tag: %u, ignoring tag.",
     358               0 :                       poTIFFDirEntry->tdir_count );
     359                 :         }
     360              81 :         else if (nDataWidth == 0 || poTIFFDirEntry->tdir_type >= TIFF_IFD )
     361                 :         {
     362                 :             CPLError( CE_Warning, CPLE_AppDefined,
     363                 :                       "Invalid or unhandled EXIF data type: %d, ignoring tag.",
     364               0 :                       poTIFFDirEntry->tdir_type );
     365                 :         }
     366                 : /* -------------------------------------------------------------------- */
     367                 : /*      This is at most 4 byte data so we can read it from tdir_offset  */
     368                 : /* -------------------------------------------------------------------- */
     369             131 :         else if (space >= 0 && space <= 4) {
     370                 : 
     371                 :             unsigned char data[4];
     372              50 :             memcpy(data, &poTIFFDirEntry->tdir_offset, 4);
     373              50 :             if (bSwabflag)
     374                 :             {
     375                 :                 // Unswab 32bit value, and reswab per data type.
     376               0 :                 TIFFSwabLong((GUInt32*) data);
     377                 : 
     378               0 :                 switch (poTIFFDirEntry->tdir_type) {
     379                 :                   case TIFF_LONG:
     380                 :                   case TIFF_SLONG:
     381                 :                   case TIFF_FLOAT:
     382               0 :                     TIFFSwabLong((GUInt32*) data);
     383               0 :                     break;
     384                 : 
     385                 :                   case TIFF_SSHORT:
     386                 :                   case TIFF_SHORT:
     387                 :                     TIFFSwabArrayOfShort((GUInt16*) data,
     388               0 :                                          poTIFFDirEntry->tdir_count);
     389                 :                   break;
     390                 : 
     391                 :                   default:
     392                 :                     break;
     393                 :                 }
     394                 :             }
     395                 : 
     396                 :             EXIFPrintData(pszTemp,
     397                 :                           poTIFFDirEntry->tdir_type,
     398              50 :                           poTIFFDirEntry->tdir_count, data);
     399                 :         }
     400                 : /* -------------------------------------------------------------------- */
     401                 : /*      The data is being read where tdir_offset point to in the file   */
     402                 : /* -------------------------------------------------------------------- */
     403              62 :         else if (space > 0 && space < MAXSTRINGLENGTH)
     404                 :         {
     405              31 :             unsigned char *data = (unsigned char *)VSIMalloc(space);
     406                 : 
     407              31 :             if (data) {
     408              31 :                 VSIFSeekL(fp,poTIFFDirEntry->tdir_offset+nTIFFHEADER,SEEK_SET);
     409              31 :                 VSIFReadL(data, 1, space, fp);
     410                 : 
     411              31 :                 if (bSwabflag) {
     412               1 :                     switch (poTIFFDirEntry->tdir_type) {
     413                 :                       case TIFF_SHORT:
     414                 :                       case TIFF_SSHORT:
     415                 :                         TIFFSwabArrayOfShort((GUInt16*) data,
     416               0 :                                              poTIFFDirEntry->tdir_count);
     417               0 :                         break;
     418                 :                       case TIFF_LONG:
     419                 :                       case TIFF_SLONG:
     420                 :                       case TIFF_FLOAT:
     421                 :                         TIFFSwabArrayOfLong((GUInt32*) data,
     422               0 :                                             poTIFFDirEntry->tdir_count);
     423               0 :                         break;
     424                 :                       case TIFF_RATIONAL:
     425                 :                       case TIFF_SRATIONAL:
     426                 :                         TIFFSwabArrayOfLong((GUInt32*) data,
     427               0 :                                             2*poTIFFDirEntry->tdir_count);
     428               0 :                         break;
     429                 :                       case TIFF_DOUBLE:
     430                 :                         TIFFSwabArrayOfDouble((double*) data,
     431               0 :                                               poTIFFDirEntry->tdir_count);
     432                 :                         break;
     433                 :                       default:
     434                 :                         break;
     435                 :                     }
     436                 :                 }
     437                 : 
     438                 :                 EXIFPrintData(pszTemp, poTIFFDirEntry->tdir_type,
     439              31 :                               poTIFFDirEntry->tdir_count, data);
     440              31 :                 CPLFree(data);
     441                 :             }
     442                 :         }
     443                 :         else
     444                 :         {
     445                 :             CPLError( CE_Warning, CPLE_AppDefined,
     446                 :                       "Invalid EXIF header size: %ld, ignoring tag.",
     447               0 :                       (long) space );
     448                 :         }
     449                 : 
     450              81 :         papszMetadata = CSLSetNameValue(papszMetadata, pszName, pszTemp);
     451                 :     }
     452              17 :     CPLFree(poTIFFDir);
     453                 : 
     454              17 :     return CE_None;
     455                 : }

Generated by: LCOV version 1.7