LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/pdf - ogrpdfdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 985 794 80.6 %
Date: 2012-12-26 Functions: 37 31 83.8 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpdfdatasource.cpp 25325 2012-12-16 21:25:25Z rouault $
       3                 :  *
       4                 :  * Project:  PDF Translator
       5                 :  * Purpose:  Implements OGRPDFDataSource class
       6                 :  * Author:   Even Rouault, even dot rouault at mines dash paris dot org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2012, Even Rouault <even dot rouault at mines dash paris dot org>
      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 "ogr_pdf.h"
      31                 : #include "ogr_p.h"
      32                 : #include "cpl_conv.h"
      33                 : 
      34                 : #include "pdfdataset.h"
      35                 : #include "pdfcreatecopy.h"
      36                 : 
      37                 : #include "memdataset.h"
      38                 : 
      39                 : #define SQUARE(x) ((x)*(x))
      40                 : #define EPSILON 1e-5
      41                 : 
      42                 : CPL_CVSID("$Id: ogrpdfdatasource.cpp 25325 2012-12-16 21:25:25Z rouault $");
      43                 : 
      44                 : /************************************************************************/
      45                 : /*                            OGRPDFLayer()                             */
      46                 : /************************************************************************/
      47                 : 
      48              20 : OGRPDFLayer::OGRPDFLayer( OGRPDFDataSource* poDS,
      49                 :                           const char * pszName,
      50                 :                           OGRSpatialReference *poSRS,
      51                 :                           OGRwkbGeometryType eGeomType ) :
      52              20 :                                 OGRMemLayer(pszName, poSRS, eGeomType )
      53                 : {
      54              20 :     this->poDS = poDS;
      55              20 :     bGeomTypeSet = FALSE;
      56              20 :     bGeomTypeMixed = FALSE;
      57              20 : }
      58                 : 
      59                 : /************************************************************************/
      60                 : /*                            CreateFeature()                           */
      61                 : /************************************************************************/
      62                 : 
      63             451 : OGRErr OGRPDFLayer::CreateFeature( OGRFeature *poFeature )
      64                 : {
      65             451 :     OGRGeometry* poGeom = poFeature->GetGeometryRef();
      66             451 :     if( !bGeomTypeMixed && poGeom != NULL )
      67                 :     {
      68             378 :         if (!bGeomTypeSet)
      69                 :         {
      70              18 :             bGeomTypeSet = TRUE;
      71              18 :             GetLayerDefn()->SetGeomType(poGeom->getGeometryType());
      72                 :         }
      73             360 :         else if (GetLayerDefn()->GetGeomType() != poGeom->getGeometryType())
      74                 :         {
      75               7 :             bGeomTypeMixed = TRUE;
      76               7 :             GetLayerDefn()->SetGeomType(wkbUnknown);
      77                 :         }
      78                 :     }
      79                 : 
      80             451 :     poDS->SetModified();
      81             451 :     return OGRMemLayer::CreateFeature(poFeature);
      82                 : }
      83                 : 
      84                 : /************************************************************************/
      85                 : /*                              Fill()                                  */
      86                 : /************************************************************************/
      87                 : 
      88              14 : void OGRPDFLayer::Fill( GDALPDFArray* poArray )
      89                 : {
      90             405 :     for(int i=0;i<poArray->GetLength();i++)
      91                 :     {
      92             391 :         GDALPDFObject* poFeatureObj = poArray->Get(i);
      93             391 :         if (poFeatureObj->GetType() != PDFObjectType_Dictionary)
      94               0 :             continue;
      95                 : 
      96             391 :         GDALPDFObject* poA = poFeatureObj->GetDictionary()->Get("A");
      97             391 :         if (!(poA != NULL && poA->GetType() == PDFObjectType_Dictionary))
      98               0 :             continue;
      99                 : 
     100             391 :         GDALPDFObject* poP = poA->GetDictionary()->Get("P");
     101             391 :         if (!(poP != NULL && poP->GetType() == PDFObjectType_Array))
     102               0 :             continue;
     103                 : 
     104             391 :         GDALPDFObject* poK = poFeatureObj->GetDictionary()->Get("K");
     105             391 :         int nK = -1;
     106             391 :         if (poK != NULL && poK->GetType() == PDFObjectType_Int)
     107             391 :             nK = poK->GetInt();
     108                 : 
     109             391 :         GDALPDFArray* poPArray = poP->GetArray();
     110                 :         int j;
     111            1424 :         for(j = 0;j<poPArray->GetLength();j++)
     112                 :         {
     113            1033 :             GDALPDFObject* poKV = poPArray->Get(j);
     114            1033 :             if (poKV->GetType() == PDFObjectType_Dictionary)
     115                 :             {
     116            1033 :                 GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
     117            1033 :                 GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
     118            1033 :                 if (poN != NULL && poN->GetType() == PDFObjectType_String &&
     119                 :                     poV != NULL)
     120                 :                 {
     121            1033 :                     int nIdx = GetLayerDefn()->GetFieldIndex( poN->GetString().c_str() );
     122            1033 :                     OGRFieldType eType = OFTString;
     123            1033 :                     if (poV->GetType() == PDFObjectType_Int)
     124               9 :                         eType = OFTInteger;
     125            1024 :                     else if (poV->GetType() == PDFObjectType_Real)
     126               1 :                         eType = OFTReal;
     127            1033 :                     if (nIdx < 0)
     128                 :                     {
     129              47 :                         OGRFieldDefn oField(poN->GetString().c_str(), eType);
     130              47 :                         CreateField(&oField);
     131                 :                     }
     132             986 :                     else if (GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != eType &&
     133               0 :                                 GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != OFTString)
     134                 :                     {
     135               0 :                         OGRFieldDefn oField(poN->GetString().c_str(), OFTString);
     136               0 :                         AlterFieldDefn( nIdx, &oField, ALTER_TYPE_FLAG );
     137                 :                     }
     138                 :                 }
     139                 :             }
     140                 :         }
     141                 : 
     142             391 :         OGRFeature* poFeature = new OGRFeature(GetLayerDefn());
     143            1424 :         for(j = 0;j<poPArray->GetLength();j++)
     144                 :         {
     145            1033 :             GDALPDFObject* poKV = poPArray->Get(j);
     146            1033 :             if (poKV->GetType() == PDFObjectType_Dictionary)
     147                 :             {
     148            1033 :                 GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
     149            1033 :                 GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
     150            1033 :                 if (poN != NULL && poN->GetType() == PDFObjectType_String &&
     151                 :                     poV != NULL)
     152                 :                 {
     153            1033 :                     if (poV->GetType() == PDFObjectType_String)
     154            1023 :                         poFeature->SetField(poN->GetString().c_str(), poV->GetString().c_str());
     155              10 :                     else if (poV->GetType() == PDFObjectType_Int)
     156               9 :                         poFeature->SetField(poN->GetString().c_str(), poV->GetInt());
     157               1 :                     else if (poV->GetType() == PDFObjectType_Real)
     158               1 :                         poFeature->SetField(poN->GetString().c_str(), poV->GetReal());
     159                 :                 }
     160                 :             }
     161                 :         }
     162                 : 
     163             391 :         if (nK >= 0)
     164                 :         {
     165             391 :             OGRGeometry* poGeom = poDS->GetGeometryFromMCID(nK);
     166             391 :             if (poGeom)
     167                 :             {
     168             391 :                 poGeom->assignSpatialReference(GetSpatialRef());
     169             391 :                 poFeature->SetGeometry(poGeom);
     170                 :             }
     171                 :         }
     172                 : 
     173             391 :         CreateFeature(poFeature);
     174                 : 
     175             391 :         delete poFeature;
     176                 :     }
     177              14 : }
     178                 : 
     179                 : /************************************************************************/
     180                 : /*                           TestCapability()                           */
     181                 : /************************************************************************/
     182                 : 
     183               0 : int OGRPDFLayer::TestCapability( const char * pszCap )
     184                 : 
     185                 : {
     186               0 :     if( EQUAL(pszCap,OLCStringsAsUTF8) )
     187               0 :         return TRUE;
     188                 :     else
     189               0 :         return OGRMemLayer::TestCapability(pszCap);
     190                 : }
     191                 : 
     192                 : /************************************************************************/
     193                 : /*                          OGRPDFDataSource()                          */
     194                 : /************************************************************************/
     195                 : 
     196               8 : OGRPDFDataSource::OGRPDFDataSource()
     197                 : 
     198                 : {
     199               8 :     pszName = NULL;
     200               8 :     papszOptions = NULL;
     201                 : 
     202               8 :     nLayers = 0;
     203               8 :     papoLayers = NULL;
     204                 : 
     205               8 :     bModified = FALSE;
     206               8 :     bWritable = FALSE;
     207                 : 
     208               8 :     poGDAL_DS = NULL;
     209               8 :     poPageObj = NULL;
     210               8 :     poCatalogObj = NULL;
     211               8 :     dfPageWidth = dfPageHeight = 0;
     212                 : 
     213               8 :     bSetStyle = CSLTestBoolean(CPLGetConfigOption("OGR_PDF_SET_STYLE", "YES"));
     214                 : 
     215               8 :     InitMapOperators();
     216               8 : }
     217                 : 
     218                 : /************************************************************************/
     219                 : /*                         ~OGRPDFDataSource()                          */
     220                 : /************************************************************************/
     221                 : 
     222               8 : OGRPDFDataSource::~OGRPDFDataSource()
     223                 : 
     224                 : {
     225               8 :     SyncToDisk();
     226                 : 
     227               8 :     CleanupIntermediateResources();
     228                 : 
     229               8 :     CPLFree( pszName );
     230               8 :     CSLDestroy( papszOptions );
     231                 : 
     232              26 :     for(int i=0;i<nLayers;i++)
     233              18 :         delete papoLayers[i];
     234               8 :     CPLFree( papoLayers );
     235               8 : }
     236                 : 
     237                 : /************************************************************************/
     238                 : /*                   CleanupIntermediateResources()                     */
     239                 : /************************************************************************/
     240                 : 
     241              14 : void OGRPDFDataSource::CleanupIntermediateResources()
     242                 : {
     243              14 :     std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.begin();
     244             405 :     for( ; oMapIter != oMapMCID.end(); ++oMapIter)
     245             391 :         delete oMapIter->second;
     246              14 :     oMapMCID.erase(oMapMCID.begin(), oMapMCID.end());
     247                 : 
     248              14 :     delete poGDAL_DS;
     249              14 :     poGDAL_DS = NULL;
     250                 : 
     251              14 :     poPageObj = NULL;
     252              14 :     poCatalogObj = NULL;
     253              14 : }
     254                 : 
     255                 : /************************************************************************/
     256                 : /*                          InitMapOperators()                          */
     257                 : /************************************************************************/
     258                 : 
     259                 : typedef struct
     260                 : {
     261                 :     char        szOpName[4];
     262                 :     char        nArgs;
     263                 : } PDFOperator;
     264                 : 
     265                 : static const PDFOperator asPDFOperators [] =
     266                 : {
     267                 :     { "b", 0 },
     268                 :     { "B", 0 },
     269                 :     { "b*", 0 },
     270                 :     { "B*", 0 },
     271                 :     { "BDC", 2 },
     272                 :     // BI
     273                 :     { "BMC", 1 },
     274                 :     // BT
     275                 :     { "BX", 0 },
     276                 :     { "c", 6 },
     277                 :     { "cm", 6 },
     278                 :     { "CS", 1 },
     279                 :     { "cs", 1 },
     280                 :     { "d", 1 }, /* we have ignored the first arg */
     281                 :     // d0
     282                 :     // d1
     283                 :     { "Do", 1 },
     284                 :     { "DP", 2 },
     285                 :     // EI
     286                 :     { "EMC", 0 },
     287                 :     // ET
     288                 :     { "EX", 0 },
     289                 :     { "f", 0 },
     290                 :     { "F", 0 },
     291                 :     { "f*", 0 },
     292                 :     { "G", 1 },
     293                 :     { "g", 1 },
     294                 :     { "gs", 1 },
     295                 :     { "h", 0 },
     296                 :     { "i", 1 },
     297                 :     // ID
     298                 :     { "j", 1 },
     299                 :     { "J", 1 },
     300                 :     { "K", 4 },
     301                 :     { "k", 4 },
     302                 :     { "l", 2 },
     303                 :     { "m", 2 },
     304                 :     { "M", 1 },
     305                 :     { "MP", 1 },
     306                 :     { "n", 0 },
     307                 :     { "q", 0 },
     308                 :     { "Q", 0 },
     309                 :     { "re", 4 },
     310                 :     { "RG", 3 },
     311                 :     { "rg", 3 },
     312                 :     { "ri", 1 },
     313                 :     { "s", 0 },
     314                 :     { "S", 0 },
     315                 :     { "SC", -1 },
     316                 :     { "sc", -1 },
     317                 :     { "SCN", -1 },
     318                 :     { "scn", -1 },
     319                 :     { "sh", 1 },
     320                 :     // T*
     321                 :     { "Tc", 1},
     322                 :     { "Td", 2},
     323                 :     { "TD", 2},
     324                 :     { "Tf", 1},
     325                 :     { "Tj", 1},
     326                 :     { "TJ", 1},
     327                 :     { "TL", 1},
     328                 :     { "Tm", 6},
     329                 :     { "Tr", 1},
     330                 :     { "Ts", 1},
     331                 :     { "Tw", 1},
     332                 :     { "Tz", 1},
     333                 :     { "v", 4 },
     334                 :     { "w", 1 },
     335                 :     { "W", 0 },
     336                 :     { "W*", 0 },
     337                 :     { "y", 4 },
     338                 :     // '
     339                 :     // "
     340                 : };
     341                 : 
     342               8 : void OGRPDFDataSource::InitMapOperators()
     343                 : {
     344            1024 :     for(size_t i=0;i<sizeof(asPDFOperators) / sizeof(asPDFOperators[0]); i++)
     345             504 :         oMapOperators[asPDFOperators[i].szOpName] = asPDFOperators[i].nArgs;
     346               8 : }
     347                 : 
     348                 : /************************************************************************/
     349                 : /*                           TestCapability()                           */
     350                 : /************************************************************************/
     351                 : 
     352               0 : int OGRPDFDataSource::TestCapability( const char * pszCap )
     353                 : 
     354                 : {
     355               0 :     if( bWritable && EQUAL(pszCap,ODsCCreateLayer) )
     356               0 :         return TRUE;
     357                 :     else
     358               0 :         return FALSE;
     359                 : }
     360                 : 
     361                 : /************************************************************************/
     362                 : /*                              GetLayer()                              */
     363                 : /************************************************************************/
     364                 : 
     365              39 : OGRLayer *OGRPDFDataSource::GetLayer( int iLayer )
     366                 : 
     367                 : {
     368              39 :     if (iLayer < 0 || iLayer >= nLayers)
     369               0 :         return NULL;
     370                 : 
     371              39 :     return papoLayers[iLayer];
     372                 : }
     373                 : 
     374                 : /************************************************************************/
     375                 : /*                            GetLayerCount()                           */
     376                 : /************************************************************************/
     377                 : 
     378              23 : int OGRPDFDataSource::GetLayerCount()
     379                 : {
     380              23 :     return nLayers;
     381                 : }
     382                 : 
     383                 : /************************************************************************/
     384                 : /*                            ExploreTree()                             */
     385                 : /************************************************************************/
     386                 : 
     387              31 : void OGRPDFDataSource::ExploreTree(GDALPDFObject* poObj, int nRecLevel)
     388                 : {
     389              31 :     if (nRecLevel == 16)
     390               0 :         return;
     391                 : 
     392              31 :     if (poObj->GetType() != PDFObjectType_Dictionary)
     393               0 :         return;
     394                 : 
     395              31 :     GDALPDFDictionary* poDict = poObj->GetDictionary();
     396                 : 
     397              31 :     GDALPDFObject* poS = poDict->Get("S");
     398              31 :     CPLString osS;
     399              31 :     if (poS != NULL && poS->GetType() == PDFObjectType_Name)
     400                 :     {
     401              27 :         osS = poS->GetName();
     402                 :     }
     403                 : 
     404              31 :     GDALPDFObject* poT = poDict->Get("T");
     405              31 :     CPLString osT;
     406              31 :     if (poT != NULL && poT->GetType() == PDFObjectType_String)
     407                 :     {
     408              26 :         osT = poT->GetString();
     409                 :     }
     410                 : 
     411              31 :     GDALPDFObject* poK = poDict->Get("K");
     412              31 :     if (poK == NULL)
     413                 :         return;
     414                 : 
     415              31 :     if (poK->GetType() == PDFObjectType_Array)
     416                 :     {
     417              30 :         GDALPDFArray* poArray = poK->GetArray();
     418             300 :         if (poArray->GetLength() > 0 &&
     419              60 :             poArray->Get(0)->GetType() == PDFObjectType_Dictionary &&
     420              90 :             poArray->Get(0)->GetDictionary()->Get("K") != NULL &&
     421             120 :             poArray->Get(0)->GetDictionary()->Get("K")->GetType() == PDFObjectType_Int)
     422                 :         {
     423              14 :             CPLString osLayerName;
     424              14 :             if (osT.size())
     425              14 :                 osLayerName = osT;
     426                 :             else
     427                 :             {
     428               0 :                 if (osS.size())
     429               0 :                     osLayerName = osS;
     430                 :                 else
     431               0 :                     osLayerName = CPLSPrintf("Layer%d", nLayers + 1);
     432                 :             }
     433                 : 
     434              14 :             const char* pszWKT = poGDAL_DS->GetProjectionRef();
     435              14 :             OGRSpatialReference* poSRS = NULL;
     436              14 :             if (pszWKT && pszWKT[0] != '\0')
     437                 :             {
     438              14 :                 poSRS = new OGRSpatialReference();
     439              14 :                 poSRS->importFromWkt((char**) &pszWKT);
     440                 :             }
     441                 : 
     442                 :             OGRPDFLayer* poLayer =
     443              14 :                 new OGRPDFLayer(this, osLayerName.c_str(), poSRS, wkbUnknown);
     444              28 :             delete poSRS;
     445                 : 
     446              14 :             poLayer->Fill(poArray);
     447                 : 
     448                 :             papoLayers = (OGRLayer**)
     449              14 :                 CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
     450              14 :             papoLayers[nLayers] = poLayer;
     451              14 :             nLayers ++;
     452                 :         }
     453                 :         else
     454                 :         {
     455              42 :             for(int i=0;i<poArray->GetLength();i++)
     456              26 :                 ExploreTree(poArray->Get(i), nRecLevel + 1);
     457                 :         }
     458                 :     }
     459               1 :     else if (poK->GetType() == PDFObjectType_Dictionary)
     460                 :     {
     461               1 :         ExploreTree(poK, nRecLevel + 1);
     462               0 :     }
     463                 : }
     464                 : 
     465                 : /************************************************************************/
     466                 : /*                        GetGeometryFromMCID()                         */
     467                 : /************************************************************************/
     468                 : 
     469             784 : OGRGeometry* OGRPDFDataSource::GetGeometryFromMCID(int nMCID)
     470                 : {
     471             784 :     std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.find(nMCID);
     472             784 :     if (oMapIter != oMapMCID.end())
     473             393 :         return oMapIter->second;
     474                 :     else
     475             391 :         return NULL;
     476                 : }
     477                 : 
     478                 : /************************************************************************/
     479                 : /*                            GraphicState                              */
     480                 : /************************************************************************/
     481                 : 
     482                 : class GraphicState
     483              55 : {
     484                 :     public:
     485                 :         double adfCM[6];
     486                 :         double adfStrokeColor[3];
     487                 :         double adfFillColor[3];
     488                 : 
     489             448 :         GraphicState()
     490                 :         {
     491             448 :             adfCM[0] = 1;
     492             448 :             adfCM[1] = 0;
     493             448 :             adfCM[2] = 0;
     494             448 :             adfCM[3] = 1;
     495             448 :             adfCM[4] = 0;
     496             448 :             adfCM[5] = 0;
     497             448 :             adfStrokeColor[0] = 0.0;
     498             448 :             adfStrokeColor[1] = 0.0;
     499             448 :             adfStrokeColor[2] = 0.0;
     500             448 :             adfFillColor[0] = 1.0;
     501             448 :             adfFillColor[1] = 1.0;
     502             448 :             adfFillColor[2] = 1.0;
     503             448 :         }
     504                 : 
     505               3 :         void MultiplyBy(double adfMatrix[6])
     506                 :         {
     507                 :             /*
     508                 :             [ a b 0 ]     [ a' b' 0]     [ aa' + bc'       ab' + bd'       0 ]
     509                 :             [ c d 0 ]  *  [ c' d' 0]  =  [ ca' + dc'       cb' + dd'       0 ]
     510                 :             [ e f 1 ]     [ e' f' 1]     [ ea' + fc' + e'  eb' + fd' + f'  1 ]
     511                 :             */
     512                 : 
     513               3 :             double a = adfCM[0];
     514               3 :             double b = adfCM[1];
     515               3 :             double c = adfCM[2];
     516               3 :             double d = adfCM[3];
     517               3 :             double e = adfCM[4];
     518               3 :             double f = adfCM[5];
     519               3 :             double ap = adfMatrix[0];
     520               3 :             double bp = adfMatrix[1];
     521               3 :             double cp = adfMatrix[2];
     522               3 :             double dp = adfMatrix[3];
     523               3 :             double ep = adfMatrix[4];
     524               3 :             double fp = adfMatrix[5];
     525               3 :             adfCM[0] = a*ap + b*cp;
     526               3 :             adfCM[1] = a*bp + b*dp;
     527               3 :             adfCM[2] = c*ap + d*cp;
     528               3 :             adfCM[3] = c*bp + d*dp;
     529               3 :             adfCM[4] = e*ap + f*cp + ep;
     530               3 :             adfCM[5] = e*bp + f*dp + fp;
     531               3 :         }
     532                 : 
     533            1781 :         void ApplyMatrix(double adfCoords[2])
     534                 :         {
     535            1781 :             double x = adfCoords[0];
     536            1781 :             double y = adfCoords[1];
     537                 : 
     538            1781 :             adfCoords[0] = x * adfCM[0] + y * adfCM[2] + adfCM[4];
     539            1781 :             adfCoords[1] = x * adfCM[1] + y * adfCM[3] + adfCM[5];
     540            1781 :         }
     541                 : };
     542                 : 
     543                 : /************************************************************************/
     544                 : /*                         PDFCoordsToSRSCoords()                       */
     545                 : /************************************************************************/
     546                 : 
     547            1928 : void OGRPDFDataSource::PDFCoordsToSRSCoords(double x, double y,
     548                 :                                             double& X, double &Y)
     549                 : {
     550            1928 :     x = x / dfPageWidth * nXSize;
     551            1928 :     y = (1 - y / dfPageHeight) * nYSize;
     552                 : 
     553            1928 :     X = adfGeoTransform[0] + x * adfGeoTransform[1] + y * adfGeoTransform[2];
     554            1928 :     Y = adfGeoTransform[3] + x * adfGeoTransform[4] + y * adfGeoTransform[5];
     555                 : 
     556            1928 :     if( fabs(X - (int)floor(X + 0.5)) < 1e-8 )
     557              64 :         X = (int)floor(X + 0.5);
     558            1928 :     if( fabs(Y - (int)floor(Y + 0.5)) < 1e-8 )
     559              65 :         Y = (int)floor(Y + 0.5);
     560            1928 : }
     561                 : 
     562                 : /************************************************************************/
     563                 : /*                         PDFGetCircleCenter()                         */
     564                 : /************************************************************************/
     565                 : 
     566                 : /* Return the center of a circle, or NULL if it is not recognized */
     567                 : 
     568             158 : static OGRPoint* PDFGetCircleCenter(OGRLineString* poLS)
     569                 : {
     570             158 :     if (poLS == NULL || poLS->getNumPoints() != 5)
     571               0 :         return NULL;
     572                 : 
     573             158 :     if (poLS->getY(0) == poLS->getY(2) &&
     574                 :         poLS->getX(1) == poLS->getX(3) &&
     575                 :         fabs((poLS->getX(0) + poLS->getX(2)) / 2 - poLS->getX(1)) < EPSILON &&
     576                 :         fabs((poLS->getY(1) + poLS->getY(3)) / 2 - poLS->getY(0)) < EPSILON)
     577                 :     {
     578                 :         return new OGRPoint((poLS->getX(0) + poLS->getX(2)) / 2,
     579              15 :                             (poLS->getY(1) + poLS->getY(3)) / 2);
     580                 :     }
     581             143 :     return NULL;
     582                 : }
     583                 : 
     584                 : /************************************************************************/
     585                 : /*                         PDFGetSquareCenter()                         */
     586                 : /************************************************************************/
     587                 : 
     588                 : /* Return the center of a square, or NULL if it is not recognized */
     589                 : 
     590             147 : static OGRPoint* PDFGetSquareCenter(OGRLineString* poLS)
     591                 : {
     592             147 :     if (poLS == NULL || poLS->getNumPoints() < 4 || poLS->getNumPoints() > 5)
     593               0 :         return NULL;
     594                 : 
     595             147 :     if (poLS->getX(0) == poLS->getX(3) &&
     596                 :         poLS->getY(0) == poLS->getY(1) &&
     597                 :         poLS->getX(1) == poLS->getX(2) &&
     598                 :         poLS->getY(2) == poLS->getY(3) &&
     599                 :         fabs(fabs(poLS->getX(0) - poLS->getX(1)) - fabs(poLS->getY(0) - poLS->getY(3))) < EPSILON)
     600                 :     {
     601                 :         return new OGRPoint((poLS->getX(0) + poLS->getX(1)) / 2,
     602               6 :                             (poLS->getY(0) + poLS->getY(3)) / 2);
     603                 :     }
     604             141 :     return NULL;
     605                 : }
     606                 : 
     607                 : /************************************************************************/
     608                 : /*                        PDFGetTriangleCenter()                        */
     609                 : /************************************************************************/
     610                 : 
     611                 : /* Return the center of a equilateral triangle, or NULL if it is not recognized */
     612                 : 
     613              16 : static OGRPoint* PDFGetTriangleCenter(OGRLineString* poLS)
     614                 : {
     615              16 :     if (poLS == NULL || poLS->getNumPoints() < 3 || poLS->getNumPoints() > 4)
     616               0 :         return NULL;
     617                 : 
     618              16 :     double dfSqD1 = SQUARE(poLS->getX(0) - poLS->getX(1)) + SQUARE(poLS->getY(0) - poLS->getY(1));
     619              16 :     double dfSqD2 = SQUARE(poLS->getX(1) - poLS->getX(2)) + SQUARE(poLS->getY(1) - poLS->getY(2));
     620              16 :     double dfSqD3 = SQUARE(poLS->getX(0) - poLS->getX(2)) + SQUARE(poLS->getY(0) - poLS->getY(2));
     621              16 :     if (fabs(dfSqD1 - dfSqD2) < EPSILON && fabs(dfSqD2 - dfSqD3) < EPSILON)
     622                 :     {
     623                 :         return new OGRPoint((poLS->getX(0) + poLS->getX(1) + poLS->getX(2)) / 3,
     624               6 :                             (poLS->getY(0) + poLS->getY(1) + poLS->getY(2)) / 3);
     625                 :     }
     626              10 :     return NULL;
     627                 : }
     628                 : 
     629                 : /************************************************************************/
     630                 : /*                          PDFGetStarCenter()                          */
     631                 : /************************************************************************/
     632                 : 
     633                 : /* Return the center of a 5-point star, or NULL if it is not recognized */
     634                 : 
     635               8 : static OGRPoint* PDFGetStarCenter(OGRLineString* poLS)
     636                 : {
     637               8 :     if (poLS == NULL || poLS->getNumPoints() < 10 || poLS->getNumPoints() > 11)
     638               0 :         return NULL;
     639                 : 
     640                 :     double dfSqD01 = SQUARE(poLS->getX(0) - poLS->getX(1)) +
     641               8 :                      SQUARE(poLS->getY(0) - poLS->getY(1));
     642                 :     double dfSqD02 = SQUARE(poLS->getX(0) - poLS->getX(2)) +
     643               8 :                        SQUARE(poLS->getY(0) - poLS->getY(2));
     644                 :     double dfSqD13 = SQUARE(poLS->getX(1) - poLS->getX(3)) +
     645               8 :                       SQUARE(poLS->getY(1) - poLS->getY(3));
     646               8 :     const double dfSin18divSin126 = 0.38196601125;
     647               8 :     int bOK = fabs(dfSqD13 / dfSqD02 - SQUARE(dfSin18divSin126)) < EPSILON;
     648              62 :     for(int i=1;i<10 && bOK;i++)
     649                 :     {
     650                 :         double dfSqDiip1 = SQUARE(poLS->getX(i) - poLS->getX((i+1)%10)) +
     651              54 :                            SQUARE(poLS->getY(i) - poLS->getY((i+1)%10));
     652              54 :         if (fabs(dfSqDiip1 - dfSqD01) > EPSILON)
     653                 :         {
     654               0 :             bOK = FALSE;
     655                 :         }
     656                 :         double dfSqDiip2 = SQUARE(poLS->getX(i) - poLS->getX((i+2)%10)) +
     657              54 :                            SQUARE(poLS->getY(i) - poLS->getY((i+2)%10));
     658              54 :         if ( (i%2) == 1 && fabs(dfSqDiip2 - dfSqD13) > EPSILON )
     659                 :         {
     660               0 :             bOK = FALSE;
     661                 :         }
     662              54 :         if ( (i%2) == 0 && fabs(dfSqDiip2 - dfSqD02) > EPSILON )
     663                 :         {
     664               0 :             bOK = FALSE;
     665                 :         }
     666                 :     }
     667               8 :     if (bOK)
     668                 :     {
     669                 :         return new OGRPoint((poLS->getX(0) + poLS->getX(2) + poLS->getX(4) +
     670                 :                              poLS->getX(6) + poLS->getX(8)) / 5,
     671                 :                             (poLS->getY(0) + poLS->getY(2) + poLS->getY(4) +
     672               6 :                              poLS->getY(6) + poLS->getY(8)) / 5);
     673                 :     }
     674               2 :     return NULL;
     675                 : }
     676                 : 
     677                 : /************************************************************************/
     678                 : /*                            UnstackTokens()                           */
     679                 : /************************************************************************/
     680                 : 
     681            1812 : int OGRPDFDataSource::UnstackTokens(const char* pszToken,
     682                 :                                     int nRequiredArgs,
     683                 :                                     char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE],
     684                 :                                     int& nTokenStackSize,
     685                 :                                     double* adfCoords)
     686                 : {
     687            1812 :     if (nTokenStackSize < nRequiredArgs)
     688                 :     {
     689               0 :         CPLDebug("PDF", "not enough arguments for %s", pszToken);
     690               0 :         return FALSE;
     691                 :     }
     692            1812 :     nTokenStackSize -= nRequiredArgs;
     693            5932 :     for(int i=0;i<nRequiredArgs;i++)
     694                 :     {
     695            4120 :         adfCoords[i] = atof(aszTokenStack[nTokenStackSize+i]);
     696                 :     }
     697            1812 :     return TRUE;
     698                 : }
     699                 : 
     700                 : /************************************************************************/
     701                 : /*                           ParseContent()                             */
     702                 : /************************************************************************/
     703                 : 
     704                 : #define NEW_SUBPATH -99
     705                 : #define CLOSE_SUBPATH -98
     706                 : #define FILL_SUBPATH -97
     707                 : 
     708             448 : OGRGeometry* OGRPDFDataSource::ParseContent(const char* pszContent,
     709                 :                                             GDALPDFObject* poResources,
     710                 :                                             int bInitBDCStack,
     711                 :                                             int bMatchQ,
     712                 :                                             std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer,
     713                 :                                             OGRPDFLayer* poCurLayer)
     714                 : {
     715                 : 
     716                 : #define PUSH(aszTokenStack, str, strlen) \
     717                 :     do \
     718                 :     { \
     719                 :         if(nTokenStackSize < TOKEN_STACK_SIZE) \
     720                 :             memcpy(aszTokenStack[nTokenStackSize ++], str, strlen + 1); \
     721                 :         else \
     722                 :         { \
     723                 :             CPLError(CE_Failure, CPLE_AppDefined, "Max token stack size reached");\
     724                 :             return NULL; \
     725                 :         }; \
     726                 :     } while(0)
     727                 : 
     728                 : #define ADD_CHAR(szToken, c) \
     729                 :     do \
     730                 :     { \
     731                 :         if(nTokenSize < MAX_TOKEN_SIZE-1) \
     732                 :         { \
     733                 :             szToken[nTokenSize ++ ] = c; \
     734                 :             szToken[nTokenSize ] = '\0'; \
     735                 :         } \
     736                 :         else \
     737                 :         { \
     738                 :             CPLError(CE_Failure, CPLE_AppDefined, "Max token size reached");\
     739                 :             return NULL; \
     740                 :         }; \
     741                 :     } while(0)
     742                 : 
     743                 :     char szToken[MAX_TOKEN_SIZE];
     744             448 :     int nTokenSize = 0;
     745                 :     char ch;
     746                 :     char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE];
     747             448 :     int nTokenStackSize = 0;
     748             448 :     int bInString = FALSE;
     749             448 :     int nBDCLevel = 0;
     750             448 :     int nParenthesisLevel = 0;
     751             448 :     int nArrayLevel = 0;
     752             448 :     int nBTLevel = 0;
     753                 :     
     754             448 :     int bCollectAllObjects = poResources != NULL && !bInitBDCStack && !bMatchQ;
     755                 : 
     756             448 :     GraphicState oGS;
     757             448 :     std::stack<GraphicState> oGSStack;
     758             448 :     std::stack<OGRPDFLayer*> oLayerStack;
     759                 : 
     760             448 :     std::vector<double> oCoords;
     761             448 :     int bHasFoundFill = FALSE;
     762             448 :     int bHasMultiPart = FALSE;
     763                 :     
     764             448 :     szToken[0] = '\0';
     765                 : 
     766             448 :     if (bInitBDCStack)
     767                 :     {
     768             391 :         PUSH(aszTokenStack, "dummy", 5);
     769             782 :         PUSH(aszTokenStack, "dummy", 5);
     770             391 :         oLayerStack.push(NULL);
     771                 :     }
     772                 : 
     773           52255 :     while((ch = *pszContent) != '\0')
     774                 :     {
     775           51750 :         int bPushToken = FALSE;
     776                 : 
     777           51750 :         if (!bInString && ch == '%')
     778                 :         {
     779                 :             /* Skip comments until end-of-line */
     780               0 :             while((ch = *pszContent) != '\0')
     781                 :             {
     782               0 :                 if (ch == '\r' || ch == '\n')
     783               0 :                     break;
     784               0 :                 pszContent ++;
     785                 :             }
     786               0 :             if (ch == 0)
     787               0 :                 break;
     788                 :         }
     789           59733 :         else if (!bInString && (ch == ' ' || ch == '\r' || ch == '\n'))
     790                 :         {
     791            7983 :             bPushToken = TRUE;
     792                 :         }
     793                 : 
     794                 :         /* Ignore arrays */
     795           43817 :         else if (!bInString && nTokenSize == 0 && ch == '[')
     796                 :         {
     797              50 :             nArrayLevel ++;
     798                 :         }
     799           43767 :         else if (!bInString && nArrayLevel && nTokenSize == 0 && ch == ']')
     800                 :         {
     801              50 :             nArrayLevel --;
     802                 :         }
     803                 : 
     804           43669 :         else if (!bInString && nTokenSize == 0 && ch == '(')
     805                 :         {
     806               2 :             bInString = TRUE;
     807               2 :             nParenthesisLevel ++;
     808               2 :             ADD_CHAR(szToken, ch);
     809                 :         }
     810           43665 :         else if (bInString && ch == '(')
     811                 :         {
     812               0 :             nParenthesisLevel ++;
     813               0 :             ADD_CHAR(szToken, ch);
     814                 :         }
     815           43667 :         else if (bInString && ch == ')')
     816                 :         {
     817               2 :             nParenthesisLevel --;
     818               2 :             ADD_CHAR(szToken, ch);
     819               2 :             if (nParenthesisLevel == 0)
     820                 :             {
     821               2 :                 bInString = FALSE;
     822               2 :                 bPushToken = TRUE;
     823                 :             }
     824                 :         }
     825           43663 :         else if (ch == '<' && pszContent[1] == '<' && nTokenSize == 0)
     826                 :         {
     827               0 :             int nDictDepth = 0;
     828                 : 
     829               0 :             while(*pszContent != '\0')
     830                 :             {
     831               0 :                 if (pszContent[0] == '<' && pszContent[1] == '<')
     832                 :                 {
     833               0 :                     ADD_CHAR(szToken, '<');
     834               0 :                     ADD_CHAR(szToken, '<');
     835               0 :                     nDictDepth ++;
     836               0 :                     pszContent += 2;
     837                 :                 }
     838               0 :                 else if (pszContent[0] == '>' && pszContent[1] == '>')
     839                 :                 {
     840               0 :                     ADD_CHAR(szToken, '>');
     841               0 :                     ADD_CHAR(szToken, '>');
     842               0 :                     nDictDepth --;
     843               0 :                     pszContent += 2;
     844               0 :                     if (nDictDepth == 0)
     845               0 :                         break;
     846                 :                 }
     847                 :                 else
     848                 :                 {
     849               0 :                     ADD_CHAR(szToken, *pszContent);
     850               0 :                     pszContent ++;
     851                 :                 }
     852                 :             }
     853               0 :             if (nDictDepth == 0)
     854                 :             {
     855               0 :                 bPushToken = TRUE;
     856               0 :                 pszContent --;
     857                 :             }
     858                 :             else
     859               0 :                 break;
     860                 :         }
     861                 :         else
     862                 :         {
     863           43663 :             ADD_CHAR(szToken, ch);
     864                 :         }
     865                 : 
     866           51750 :         pszContent ++;
     867           51750 :         if (pszContent[0] == '\0')
     868              57 :             bPushToken = TRUE;
     869                 : 
     870                 : #define EQUAL1(szToken, s) (szToken[0] == s[0] && szToken[1] == '\0')
     871                 : #define EQUAL2(szToken, s) (szToken[0] == s[0] && szToken[1] == s[1] && szToken[2] == '\0')
     872                 : #define EQUAL3(szToken, s) (szToken[0] == s[0] && szToken[1] == s[1] && szToken[2] == s[2] && szToken[3] == '\0')
     873                 : 
     874           51750 :         if (bPushToken && nTokenSize)
     875                 :         {
     876            8038 :             if (EQUAL2(szToken, "BI"))
     877                 :             {
     878               0 :                 while(*pszContent != '\0')
     879                 :                 {
     880               0 :                     if( pszContent[0] == 'E' && pszContent[1] == 'I' && pszContent[2] == ' ' )
     881                 :                     {
     882               0 :                         break;
     883                 :                     }
     884               0 :                     pszContent ++;
     885                 :                 }
     886               0 :                 if( pszContent[0] == 'E' )
     887               0 :                     pszContent += 3;
     888                 :                 else
     889               0 :                     return NULL;
     890                 :             }
     891            8435 :             else if (EQUAL3(szToken, "BDC"))
     892                 :             {
     893             397 :                 if (nTokenStackSize < 2)
     894                 :                 {
     895                 :                     CPLDebug("PDF",
     896                 :                                 "not enough arguments for %s",
     897               0 :                                 szToken);
     898               0 :                     return NULL;
     899                 :                 }
     900             397 :                 nTokenStackSize -= 2;
     901             397 :                 const char* pszOC = aszTokenStack[nTokenStackSize];
     902             397 :                 const char* pszOCGName = aszTokenStack[nTokenStackSize+1];
     903                 : 
     904             397 :                 nBDCLevel ++;
     905                 : 
     906             397 :                 if( EQUAL3(pszOC, "/OC") && pszOCGName[0] == '/' )
     907                 :                 {
     908                 :                     std::map<CPLString, OGRPDFLayer*>::iterator oIter =
     909               6 :                         oMapPropertyToLayer.find(pszOCGName + 1);
     910               6 :                     if( oIter != oMapPropertyToLayer.end() )
     911                 :                     {
     912               6 :                         poCurLayer = oIter->second;
     913                 :                         //CPLDebug("PDF", "Cur layer : %s", poCurLayer->GetName());
     914                 :                     }
     915                 :                 }
     916                 : 
     917             397 :                 oLayerStack.push(poCurLayer);
     918                 :                 //CPLDebug("PDF", "%s %s BDC", osOC.c_str(), osOCGName.c_str());
     919                 :             }
     920            7647 :             else if (EQUAL3(szToken, "EMC"))
     921                 :             {
     922                 :                 //CPLDebug("PDF", "EMC");
     923             374 :                 if( !oLayerStack.empty() )
     924                 :                 {
     925             374 :                     oLayerStack.pop();
     926             374 :                     if( !oLayerStack.empty() )
     927             370 :                         poCurLayer = oLayerStack.top();
     928                 :                     else
     929               4 :                         poCurLayer = NULL;
     930                 : 
     931                 :                     /*if (poCurLayer)
     932                 :                     {
     933                 :                         CPLDebug("PDF", "Cur layer : %s", poCurLayer->GetName());
     934                 :                     }*/
     935                 :                 }
     936                 :                 else
     937                 :                 {
     938               0 :                     CPLDebug("PDF", "Should not happen at line %d", __LINE__);
     939               0 :                     poCurLayer = NULL;
     940                 :                     //return NULL;
     941                 :                 }
     942                 : 
     943             374 :                 nBDCLevel --;
     944             374 :                 if (nBDCLevel == 0 && bInitBDCStack)
     945             368 :                     break;
     946                 :             }
     947                 : 
     948                 :             /* Ignore any text stuff */
     949            7269 :             else if (EQUAL2(szToken, "BT"))
     950               2 :                 nBTLevel ++;
     951            7267 :             else if (EQUAL2(szToken, "ET"))
     952                 :             {
     953               2 :                 nBTLevel --;
     954               2 :                 if (nBTLevel < 0)
     955                 :                 {
     956               0 :                     CPLDebug("PDF", "Should not happen at line %d", __LINE__);
     957               0 :                     return NULL;
     958                 :                 }
     959                 :             }
     960            7263 :             else if (!nArrayLevel && !nBTLevel)
     961                 :             {
     962            7237 :                 int bEmitFeature = FALSE;
     963                 : 
     964            7237 :                 if( szToken[0] < 'A' )
     965                 :                 {
     966            4493 :                     PUSH(aszTokenStack, szToken, nTokenSize);
     967                 :                 }
     968            2799 :                 else if (EQUAL1(szToken, "q"))
     969                 :                 {
     970              55 :                     oGSStack.push(oGS);
     971                 :                 }
     972            2744 :                 else if (EQUAL1(szToken, "Q"))
     973                 :                 {
     974              55 :                     if (oGSStack.empty())
     975                 :                     {
     976               0 :                         CPLDebug("PDF", "not enough arguments for %s", szToken);
     977               0 :                         return NULL;
     978                 :                     }
     979                 : 
     980              55 :                     oGS = oGSStack.top();
     981              55 :                     oGSStack.pop();
     982                 : 
     983              55 :                     if (oGSStack.empty() && bMatchQ)
     984               0 :                         break;
     985                 :                 }
     986            2637 :                 else if (EQUAL2(szToken, "cm"))
     987                 :                 {
     988                 :                     double adfMatrix[6];
     989               3 :                     if (!UnstackTokens(szToken, 6, aszTokenStack, nTokenStackSize, adfMatrix))
     990                 :                     {
     991               0 :                         CPLDebug("PDF", "Should not happen at line %d", __LINE__);
     992               0 :                         return NULL;
     993                 :                     }
     994                 : 
     995               3 :                     oGS.MultiplyBy(adfMatrix);
     996                 :                 }
     997            5346 :                 else if (EQUAL1(szToken, "b") || /* closepath, fill, stroke */
     998            2687 :                          EQUAL2(szToken, "b*")   /* closepath, eofill, stroke */)
     999                 :                 {
    1000              28 :                     if (!(oCoords.size() > 0 &&
    1001                 :                           oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
    1002                 :                           oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
    1003                 :                     {
    1004              21 :                         oCoords.push_back(CLOSE_SUBPATH);
    1005              21 :                         oCoords.push_back(CLOSE_SUBPATH);
    1006                 :                     }
    1007              28 :                     oCoords.push_back(FILL_SUBPATH);
    1008              28 :                     oCoords.push_back(FILL_SUBPATH);
    1009              28 :                     bHasFoundFill = TRUE;
    1010                 : 
    1011              28 :                     bEmitFeature = TRUE;
    1012                 :                 }
    1013           12418 :                 else if (EQUAL1(szToken, "B") ||  /* fill, stroke */
    1014            2404 :                          EQUAL2(szToken, "B*") || /* eofill, stroke */
    1015            2404 :                          EQUAL1(szToken, "f") ||  /* fill */
    1016            2404 :                          EQUAL1(szToken, "F") ||  /* fill */
    1017            2404 :                          EQUAL2(szToken, "f*")    /* eofill */ )
    1018                 :                 {
    1019             199 :                     oCoords.push_back(FILL_SUBPATH);
    1020             199 :                     oCoords.push_back(FILL_SUBPATH);
    1021             199 :                     bHasFoundFill = TRUE;
    1022                 : 
    1023             199 :                     bEmitFeature = TRUE;
    1024                 :                 }
    1025            2416 :                 else if (EQUAL1(szToken, "h")) /* close subpath */
    1026                 :                 {
    1027              12 :                     if (!(oCoords.size() > 0 &&
    1028                 :                           oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
    1029                 :                           oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
    1030                 :                     {
    1031              12 :                         oCoords.push_back(CLOSE_SUBPATH);
    1032              12 :                         oCoords.push_back(CLOSE_SUBPATH);
    1033                 :                     }
    1034                 :                 }
    1035            2392 :                 else if (EQUAL1(szToken, "n")) /* new subpath without stroking or filling */
    1036                 :                 {
    1037               0 :                     oCoords.resize(0);
    1038                 :                 }
    1039            2404 :                 else if (EQUAL1(szToken, "s")) /* close and stroke */
    1040                 :                 {
    1041              12 :                     if (!(oCoords.size() > 0 &&
    1042                 :                           oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
    1043                 :                           oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
    1044                 :                     {
    1045              12 :                         oCoords.push_back(CLOSE_SUBPATH);
    1046              12 :                         oCoords.push_back(CLOSE_SUBPATH);
    1047                 :                     }
    1048                 : 
    1049              12 :                     bEmitFeature = TRUE;
    1050                 :                 }
    1051            2590 :                 else if (EQUAL1(szToken, "S")) /* stroke */
    1052                 :                 {
    1053             210 :                     bEmitFeature = TRUE;
    1054                 :                 }
    1055            3747 :                 else if (EQUAL1(szToken, "m") || EQUAL1(szToken, "l"))
    1056                 :                 {
    1057                 :                     double adfCoords[2];
    1058            1577 :                     if (!UnstackTokens(szToken, 2, aszTokenStack, nTokenStackSize, adfCoords))
    1059                 :                     {
    1060               0 :                         CPLDebug("PDF", "Should not happen at line %d", __LINE__);
    1061               0 :                         return NULL;
    1062                 :                     }
    1063                 : 
    1064            1577 :                     if (EQUAL1(szToken, "m"))
    1065                 :                     {
    1066             388 :                         if (oCoords.size() != 0)
    1067              42 :                             bHasMultiPart = TRUE;
    1068             388 :                         oCoords.push_back(NEW_SUBPATH);
    1069             388 :                         oCoords.push_back(NEW_SUBPATH);
    1070                 :                     }
    1071                 : 
    1072            1577 :                     oGS.ApplyMatrix(adfCoords);
    1073            1577 :                     oCoords.push_back(adfCoords[0]);
    1074            1577 :                     oCoords.push_back(adfCoords[1]);
    1075                 :                 }
    1076             653 :                 else if (EQUAL1(szToken, "c")) /* Bezier curve */
    1077                 :                 {
    1078                 :                     double adfCoords[6];
    1079              60 :                     if (!UnstackTokens(szToken, 6, aszTokenStack, nTokenStackSize, adfCoords))
    1080                 :                     {
    1081               0 :                         CPLDebug("PDF", "Should not happen at line %d", __LINE__);
    1082               0 :                         return NULL;
    1083                 :                     }
    1084                 : 
    1085              60 :                     oGS.ApplyMatrix(adfCoords + 4);
    1086              60 :                     oCoords.push_back(adfCoords[4]);
    1087              60 :                     oCoords.push_back(adfCoords[5]);
    1088                 :                 }
    1089             533 :                 else if (EQUAL1(szToken, "v") || EQUAL1(szToken, "y")) /* Bezier curve */
    1090                 :                 {
    1091                 :                     double adfCoords[4];
    1092               0 :                     if (!UnstackTokens(szToken, 4, aszTokenStack, nTokenStackSize, adfCoords))
    1093                 :                     {
    1094               0 :                         CPLDebug("PDF", "Should not happen at line %d", __LINE__);
    1095               0 :                         return NULL;
    1096                 :                     }
    1097                 : 
    1098               0 :                     oGS.ApplyMatrix(adfCoords + 2);
    1099               0 :                     oCoords.push_back(adfCoords[2]);
    1100               0 :                     oCoords.push_back(adfCoords[3]);
    1101                 :                 }
    1102             605 :                 else if (EQUAL2(szToken, "re")) /* Rectangle */
    1103                 :                 {
    1104                 :                     double adfCoords[4];
    1105              72 :                     if (!UnstackTokens(szToken, 4, aszTokenStack, nTokenStackSize, adfCoords))
    1106                 :                     {
    1107               0 :                         CPLDebug("PDF", "Should not happen at line %d", __LINE__);
    1108               0 :                         return NULL;
    1109                 :                     }
    1110                 : 
    1111              72 :                     adfCoords[2] += adfCoords[0];
    1112              72 :                     adfCoords[3] += adfCoords[1];
    1113                 : 
    1114              72 :                     oGS.ApplyMatrix(adfCoords);
    1115              72 :                     oGS.ApplyMatrix(adfCoords + 2);
    1116                 : 
    1117              72 :                     if (oCoords.size() != 0)
    1118               0 :                         bHasMultiPart = TRUE;
    1119              72 :                     oCoords.push_back(NEW_SUBPATH);
    1120              72 :                     oCoords.push_back(NEW_SUBPATH);
    1121              72 :                     oCoords.push_back(adfCoords[0]);
    1122              72 :                     oCoords.push_back(adfCoords[1]);
    1123              72 :                     oCoords.push_back(adfCoords[2]);
    1124              72 :                     oCoords.push_back(adfCoords[1]);
    1125              72 :                     oCoords.push_back(adfCoords[2]);
    1126              72 :                     oCoords.push_back(adfCoords[3]);
    1127              72 :                     oCoords.push_back(adfCoords[0]);
    1128              72 :                     oCoords.push_back(adfCoords[3]);
    1129              72 :                     oCoords.push_back(CLOSE_SUBPATH);
    1130              72 :                     oCoords.push_back(CLOSE_SUBPATH);
    1131                 :                 }
    1132                 : 
    1133             495 :                 else if (EQUAL2(szToken, "Do"))
    1134                 :                 {
    1135              58 :                     if (nTokenStackSize == 0)
    1136                 :                     {
    1137                 :                         CPLDebug("PDF",
    1138                 :                                  "not enough arguments for %s",
    1139               0 :                                  szToken);
    1140               0 :                         return NULL;
    1141                 :                     }
    1142                 : 
    1143              58 :                     CPLString osObjectName = aszTokenStack[--nTokenStackSize];
    1144                 : 
    1145              58 :                     if (osObjectName[0] != '/')
    1146                 :                     {
    1147               0 :                         CPLDebug("PDF", "Should not happen at line %d", __LINE__);
    1148               0 :                         return NULL;
    1149                 :                     }
    1150                 : 
    1151              58 :                     if (poResources == NULL)
    1152                 :                     {
    1153               3 :                         if (osObjectName.find("/SymImage") == 0)
    1154                 :                         {
    1155               3 :                             oCoords.push_back(oGS.adfCM[4] + oGS.adfCM[0] / 2);
    1156               3 :                             oCoords.push_back(oGS.adfCM[5] + oGS.adfCM[3] / 2);
    1157                 : 
    1158               3 :                             szToken[0] = '\0';
    1159               3 :                             nTokenSize = 0;
    1160                 : 
    1161               3 :                             if( poCurLayer != NULL)
    1162               2 :                                 bEmitFeature = TRUE;
    1163                 :                             else
    1164               1 :                                 continue;
    1165                 :                         }
    1166                 :                         else
    1167                 :                         {
    1168                 :                             //CPLDebug("PDF", "Should not happen at line %d", __LINE__);
    1169               0 :                             return NULL;
    1170                 :                         }
    1171                 :                     }
    1172                 : 
    1173              57 :                     if( !bEmitFeature )
    1174                 :                     {
    1175                 :                         GDALPDFObject* poXObject =
    1176              55 :                             poResources->GetDictionary()->Get("XObject");
    1177             110 :                         if (poXObject == NULL ||
    1178              55 :                             poXObject->GetType() != PDFObjectType_Dictionary)
    1179                 :                         {
    1180               0 :                             CPLDebug("PDF", "Should not happen at line %d", __LINE__);
    1181               0 :                             return NULL;
    1182                 :                         }
    1183                 : 
    1184                 :                         GDALPDFObject* poObject =
    1185              55 :                             poXObject->GetDictionary()->Get(osObjectName.c_str() + 1);
    1186              55 :                         if (poObject == NULL)
    1187                 :                         {
    1188               0 :                             CPLDebug("PDF", "Should not happen at line %d", __LINE__);
    1189               0 :                             return NULL;
    1190                 :                         }
    1191                 : 
    1192              55 :                         int bParseStream = TRUE;
    1193                 :                         /* Check if the object is an image. If so, no need to try to parse */
    1194                 :                         /* it. */
    1195              55 :                         if (poObject->GetType() == PDFObjectType_Dictionary)
    1196                 :                         {
    1197              55 :                             GDALPDFObject* poSubtype = poObject->GetDictionary()->Get("Subtype");
    1198             165 :                             if (poSubtype != NULL &&
    1199              55 :                                 poSubtype->GetType() == PDFObjectType_Name &&
    1200              55 :                                 poSubtype->GetName() == "Image" )
    1201                 :                             {
    1202               0 :                                 bParseStream = FALSE;
    1203                 :                             }
    1204                 :                         }
    1205                 : 
    1206              55 :                         if( bParseStream )
    1207                 :                         {
    1208              55 :                             GDALPDFStream* poStream = poObject->GetStream();
    1209              55 :                             if (!poStream)
    1210                 :                             {
    1211               0 :                                 CPLDebug("PDF", "Should not happen at line %d", __LINE__);
    1212               0 :                                 return NULL;
    1213                 :                             }
    1214                 : 
    1215              55 :                             char* pszStr = poStream->GetBytes();
    1216              55 :                             if( pszStr )
    1217                 :                             {
    1218                 :                                 OGRGeometry* poGeom = ParseContent(pszStr, NULL, FALSE, FALSE,
    1219              55 :                                                                 oMapPropertyToLayer, poCurLayer);
    1220              55 :                                 CPLFree(pszStr);
    1221              55 :                                 if (poGeom && !bCollectAllObjects)
    1222              23 :                                     return poGeom;
    1223              32 :                                 delete poGeom;
    1224                 :                             }
    1225                 :                         }
    1226               0 :                     }
    1227                 :                 }
    1228             503 :                 else if( EQUAL2(szToken, "RG") || EQUAL2(szToken, "rg") )
    1229                 :                 {
    1230             100 :                     double* padf = ( EQUAL2(szToken, "RG") ) ? oGS.adfStrokeColor : oGS.adfFillColor;
    1231             100 :                     if (!UnstackTokens(szToken, 3, aszTokenStack, nTokenStackSize, padf))
    1232                 :                     {
    1233               0 :                         CPLDebug("PDF", "Should not happen at line %d", __LINE__);
    1234               0 :                         return NULL;
    1235                 :                     }
    1236                 :                 }
    1237             303 :                 else if (oMapOperators.find(szToken) != oMapOperators.end())
    1238                 :                 {
    1239             303 :                     int nArgs = oMapOperators[szToken];
    1240             303 :                     if (nArgs < 0)
    1241                 :                     {
    1242               0 :                         while( nTokenStackSize != 0 )
    1243                 :                         {
    1244               0 :                             CPLString osTopToken = aszTokenStack[--nTokenStackSize];
    1245               0 :                             if (oMapOperators.find(osTopToken) != oMapOperators.end())
    1246                 :                                 break;
    1247                 :                         }
    1248                 :                     }
    1249                 :                     else
    1250                 :                     {
    1251             303 :                         if( nArgs > nTokenStackSize )
    1252                 :                         {
    1253                 :                             CPLDebug("PDF",
    1254                 :                                     "not enough arguments for %s",
    1255               0 :                                     szToken);
    1256               0 :                             return NULL;
    1257                 :                         }
    1258             303 :                         nTokenStackSize -= nArgs;
    1259                 :                     }
    1260                 :                 }
    1261                 :                 else
    1262                 :                 {
    1263               0 :                     PUSH(aszTokenStack, szToken, nTokenSize);
    1264                 :                 }
    1265                 : 
    1266            7213 :                 if( bEmitFeature && poCurLayer != NULL)
    1267                 :                 {
    1268              30 :                     OGRGeometry* poGeom = BuildGeometry(oCoords, bHasFoundFill, bHasMultiPart);
    1269              30 :                     bHasFoundFill = bHasMultiPart = FALSE;
    1270              30 :                     if (poGeom)
    1271                 :                     {
    1272              30 :                         OGRFeature* poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
    1273              30 :                         if( bSetStyle )
    1274                 :                         {
    1275              30 :                             OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
    1276              32 :                             if( eType == wkbLineString || eType == wkbMultiLineString )
    1277                 :                             {
    1278                 :                                 poFeature->SetStyleString(CPLSPrintf("PEN(c:#%02X%02X%02X)",
    1279               2 :                                                                     (int)(oGS.adfStrokeColor[0] * 255 + 0.5),
    1280               2 :                                                                     (int)(oGS.adfStrokeColor[1] * 255 + 0.5),
    1281               6 :                                                                     (int)(oGS.adfStrokeColor[2] * 255 + 0.5)));
    1282                 :                             }
    1283              28 :                             else if( eType == wkbPolygon || eType == wkbMultiPolygon )
    1284                 :                             {
    1285                 :                                 poFeature->SetStyleString(CPLSPrintf("PEN(c:#%02X%02X%02X);BRUSH(fc:#%02X%02X%02X)",
    1286               4 :                                                                     (int)(oGS.adfStrokeColor[0] * 255 + 0.5),
    1287               4 :                                                                     (int)(oGS.adfStrokeColor[1] * 255 + 0.5),
    1288               4 :                                                                     (int)(oGS.adfStrokeColor[2] * 255 + 0.5),
    1289               4 :                                                                     (int)(oGS.adfFillColor[0] * 255 + 0.5),
    1290               4 :                                                                     (int)(oGS.adfFillColor[1] * 255 + 0.5),
    1291              24 :                                                                     (int)(oGS.adfFillColor[2] * 255 + 0.5)));
    1292                 :                             }
    1293                 :                         }
    1294              30 :                         poGeom->assignSpatialReference(poCurLayer->GetSpatialRef());
    1295              30 :                         poFeature->SetGeometryDirectly(poGeom);
    1296              30 :                         poCurLayer->CreateFeature(poFeature);
    1297              30 :                         delete poFeature;
    1298                 :                     }
    1299                 : 
    1300              30 :                     oCoords.resize(0);
    1301                 :                 }
    1302                 :             }
    1303                 : 
    1304            7646 :             szToken[0] = '\0';
    1305            7646 :             nTokenSize = 0;
    1306                 :         }
    1307                 :     }
    1308                 : 
    1309             425 :     if (nTokenStackSize != 0)
    1310                 :     {
    1311               0 :         while(nTokenStackSize != 0)
    1312                 :         {
    1313               0 :             nTokenStackSize--;
    1314                 :             CPLDebug("PDF",
    1315                 :                      "Remaing values in stack : %s",
    1316               0 :                      aszTokenStack[nTokenStackSize]);
    1317                 :         }
    1318               0 :         return  NULL;
    1319                 :     }
    1320                 : 
    1321             425 :     if (bCollectAllObjects)
    1322               2 :         return NULL;
    1323                 : 
    1324             423 :     return BuildGeometry(oCoords, bHasFoundFill, bHasMultiPart);
    1325                 : }
    1326                 : 
    1327                 : /************************************************************************/
    1328                 : /*                           BuildGeometry()                            */
    1329                 : /************************************************************************/
    1330                 : 
    1331             453 : OGRGeometry* OGRPDFDataSource::BuildGeometry(std::vector<double>& oCoords,
    1332                 :                                              int bHasFoundFill,
    1333                 :                                              int bHasMultiPart)
    1334                 : {
    1335             453 :     OGRGeometry* poGeom = NULL;
    1336                 : 
    1337             453 :     if (!oCoords.size())
    1338              32 :         return NULL;
    1339                 : 
    1340             421 :     if (oCoords.size() == 2)
    1341                 :     {
    1342                 :         double X, Y;
    1343               3 :         PDFCoordsToSRSCoords(oCoords[0], oCoords[1], X, Y);
    1344               3 :         poGeom = new OGRPoint(X, Y);
    1345                 :     }
    1346             418 :     else if (!bHasFoundFill)
    1347                 :     {
    1348             191 :         OGRLineString* poLS = NULL;
    1349             191 :         OGRMultiLineString* poMLS = NULL;
    1350             191 :         if (bHasMultiPart)
    1351                 :         {
    1352              11 :             poMLS = new OGRMultiLineString();
    1353              11 :             poGeom = poMLS;
    1354                 :         }
    1355                 : 
    1356            1060 :         for(size_t i=0;i<oCoords.size();i+=2)
    1357                 :         {
    1358             869 :             if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
    1359                 :             {
    1360             228 :                 poLS = new OGRLineString();
    1361             228 :                 if (poMLS)
    1362              48 :                     poMLS->addGeometryDirectly(poLS);
    1363                 :                 else
    1364             180 :                     poGeom = poLS;
    1365                 :             }
    1366             641 :             else if (oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH)
    1367                 :             {
    1368              12 :                 if (poLS && poLS->getNumPoints() >= 2 &&
    1369                 :                     !(poLS->getX(0) == poLS->getX(poLS->getNumPoints()-1) &&
    1370                 :                         poLS->getY(0) == poLS->getY(poLS->getNumPoints()-1)))
    1371                 :                 {
    1372               9 :                     poLS->addPoint(poLS->getX(0), poLS->getY(0));
    1373                 :                 }
    1374                 :             }
    1375             629 :             else if (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH)
    1376                 :             {
    1377                 :                 /* Should not happen */
    1378                 :             }
    1379                 :             else
    1380                 :             {
    1381             629 :                 if (poLS)
    1382                 :                 {
    1383                 :                     double X, Y;
    1384             629 :                     PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
    1385                 : 
    1386             629 :                     poLS->addPoint(X, Y);
    1387                 :                 }
    1388                 :             }
    1389                 :         }
    1390                 : 
    1391                 :         /* Recognize points as outputed by GDAL (ogr-sym-2 : circle (not filled)) */
    1392             191 :         OGRGeometry* poCenter = NULL;
    1393             191 :         if (poCenter == NULL && poLS != NULL && poLS->getNumPoints() == 5)
    1394                 :         {
    1395               6 :             poCenter = PDFGetCircleCenter(poLS);
    1396                 :         }
    1397                 : 
    1398                 :         /* Recognize points as outputed by GDAL (ogr-sym-4: square (not filled)) */
    1399             191 :         if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 4 || poLS->getNumPoints() == 5))
    1400                 :         {
    1401               7 :             poCenter = PDFGetSquareCenter(poLS);
    1402                 :         }
    1403                 : 
    1404                 :         /* Recognize points as outputed by GDAL (ogr-sym-6: triangle (not filled)) */
    1405             191 :         if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 3 || poLS->getNumPoints() == 4))
    1406                 :         {
    1407              13 :             poCenter = PDFGetTriangleCenter(poLS);
    1408                 :         }
    1409                 : 
    1410                 :         /* Recognize points as outputed by GDAL (ogr-sym-8: star (not filled)) */
    1411             191 :         if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 10 || poLS->getNumPoints() == 11))
    1412                 :         {
    1413               4 :             poCenter = PDFGetStarCenter(poLS);
    1414                 :         }
    1415                 : 
    1416             191 :         if (poCenter == NULL && poMLS != NULL && poMLS->getNumGeometries() == 2)
    1417                 :         {
    1418               6 :             OGRLineString* poLS1 = (OGRLineString* )poMLS->getGeometryRef(0);
    1419               6 :             OGRLineString* poLS2 = (OGRLineString* )poMLS->getGeometryRef(1);
    1420                 : 
    1421                 :             /* Recognize points as outputed by GDAL (ogr-sym-0: cross (+) ) */
    1422               6 :             if (poLS1->getNumPoints() == 2 && poLS2->getNumPoints() == 2 &&
    1423                 :                 poLS1->getY(0) == poLS1->getY(1) &&
    1424                 :                 poLS2->getX(0) == poLS2->getX(1) &&
    1425                 :                 fabs(fabs(poLS1->getX(0) - poLS1->getX(1)) - fabs(poLS2->getY(0) - poLS2->getY(1))) < EPSILON &&
    1426                 :                 fabs((poLS1->getX(0) + poLS1->getX(1)) / 2 - poLS2->getX(0)) < EPSILON &&
    1427                 :                 fabs((poLS2->getY(0) + poLS2->getY(1)) / 2 - poLS1->getY(0)) < EPSILON)
    1428                 :             {
    1429               3 :                 poCenter = new OGRPoint(poLS2->getX(0), poLS1->getY(0));
    1430                 :             }
    1431                 :             /* Recognize points as outputed by GDAL (ogr-sym-1: diagcross (X) ) */
    1432               3 :             else if (poLS1->getNumPoints() == 2 && poLS2->getNumPoints() == 2 &&
    1433                 :                      poLS1->getX(0) == poLS2->getX(0) &&
    1434                 :                      poLS1->getY(0) == poLS2->getY(1) &&
    1435                 :                      poLS1->getX(1) == poLS2->getX(1) &&
    1436                 :                      poLS1->getY(1) == poLS2->getY(0) &&
    1437                 :                      fabs(fabs(poLS1->getX(0) - poLS1->getX(1)) - fabs(poLS1->getY(0) - poLS1->getY(1))) < EPSILON)
    1438                 :             {
    1439                 :                 poCenter = new OGRPoint((poLS1->getX(0) + poLS1->getX(1)) / 2,
    1440               3 :                                         (poLS1->getY(0) + poLS1->getY(1)) / 2);
    1441                 :             }
    1442                 :         }
    1443                 : 
    1444             191 :         if (poCenter)
    1445                 :         {
    1446              18 :             delete poGeom;
    1447              18 :             poGeom = poCenter;
    1448                 :         }
    1449                 :     }
    1450                 :     else
    1451                 :     {
    1452             227 :         OGRLinearRing* poLS = NULL;
    1453             227 :         int nPolys = 0;
    1454             227 :         OGRGeometry** papoPoly = NULL;
    1455                 : 
    1456            1901 :         for(size_t i=0;i<oCoords.size();i+=2)
    1457                 :         {
    1458            1767 :             if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
    1459                 :             {
    1460             232 :                 delete poLS;
    1461             232 :                 poLS = new OGRLinearRing();
    1462                 :             }
    1463            1535 :             else if ((oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH) ||
    1464                 :                         (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH))
    1465                 :             {
    1466             239 :                 if (poLS)
    1467                 :                 {
    1468             232 :                     poLS->closeRings();
    1469                 : 
    1470             232 :                     OGRPoint* poCenter = NULL;
    1471                 : 
    1472             232 :                     if (nPolys == 0 &&
    1473                 :                         poLS &&
    1474                 :                         poLS->getNumPoints() == 5)
    1475                 :                     {
    1476                 :                         /* Recognize points as outputed by GDAL (ogr-sym-3 : circle (filled)) */
    1477             152 :                         poCenter = PDFGetCircleCenter(poLS);
    1478                 : 
    1479                 :                         /* Recognize points as outputed by GDAL (ogr-sym-5: square (filled)) */
    1480             152 :                         if (poCenter == NULL)
    1481             140 :                             poCenter = PDFGetSquareCenter(poLS);
    1482                 : 
    1483                 :                         /* ESRI points */
    1484             152 :                         if (poCenter == NULL &&
    1485                 :                             oCoords.size() == 14 &&
    1486                 :                             poLS->getY(0) == poLS->getY(1) &&
    1487                 :                             poLS->getX(1) == poLS->getX(2) &&
    1488                 :                             poLS->getY(2) == poLS->getY(3) &&
    1489                 :                             poLS->getX(3) == poLS->getX(0))
    1490                 :                         {
    1491                 :                             poCenter = new OGRPoint((poLS->getX(0) + poLS->getX(1)) / 2,
    1492              72 :                                                     (poLS->getY(0) + poLS->getY(2)) / 2);
    1493                 :                         }
    1494                 :                     }
    1495                 :                     /* Recognize points as outputed by GDAL (ogr-sym-7: triangle (filled)) */
    1496              80 :                     else if (nPolys == 0 &&
    1497                 :                              poLS &&
    1498                 :                              poLS->getNumPoints() == 4)
    1499                 :                     {
    1500               3 :                         poCenter = PDFGetTriangleCenter(poLS);
    1501                 :                     }
    1502                 :                     /* Recognize points as outputed by GDAL (ogr-sym-9: star (filled)) */
    1503              77 :                     else if (nPolys == 0 &&
    1504                 :                              poLS &&
    1505                 :                              poLS->getNumPoints() == 11)
    1506                 :                     {
    1507               4 :                         poCenter = PDFGetStarCenter(poLS);
    1508                 :                     }
    1509                 : 
    1510             232 :                     if (poCenter)
    1511                 :                     {
    1512              93 :                         poGeom = poCenter;
    1513              93 :                         break;
    1514                 :                     }
    1515                 : 
    1516             139 :                     if (poLS->getNumPoints() >= 3)
    1517                 :                     {
    1518             139 :                         OGRPolygon* poPoly =  new OGRPolygon();
    1519             139 :                         poPoly->addRingDirectly(poLS);
    1520             139 :                         poLS = NULL;
    1521                 : 
    1522             139 :                         papoPoly = (OGRGeometry**) CPLRealloc(papoPoly, (nPolys + 1) * sizeof(OGRGeometry*));
    1523             139 :                         papoPoly[nPolys ++] = poPoly;
    1524                 :                     }
    1525                 :                     else
    1526                 :                     {
    1527               0 :                         delete poLS;
    1528               0 :                         poLS = NULL;
    1529                 :                     }
    1530                 :                 }
    1531                 :             }
    1532                 :             else
    1533                 :             {
    1534            1296 :                 if (poLS)
    1535                 :                 {
    1536                 :                     double X, Y;
    1537            1296 :                     PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
    1538                 : 
    1539            1296 :                     poLS->addPoint(X, Y);
    1540                 :                 }
    1541                 :             }
    1542                 :         }
    1543                 : 
    1544             227 :         delete poLS;
    1545                 : 
    1546                 :         int bIsValidGeometry;
    1547             233 :         if (nPolys == 2 &&
    1548               3 :             ((OGRPolygon*)papoPoly[0])->getNumInteriorRings() == 0 &&
    1549               3 :             ((OGRPolygon*)papoPoly[1])->getNumInteriorRings() == 0)
    1550                 :         {
    1551               3 :             OGRLinearRing* poRing0 = ((OGRPolygon*)papoPoly[0])->getExteriorRing();
    1552               3 :             OGRLinearRing* poRing1 = ((OGRPolygon*)papoPoly[1])->getExteriorRing();
    1553               3 :             if (poRing0->getNumPoints() == poRing1->getNumPoints())
    1554                 :             {
    1555               3 :                 int bSameRing = TRUE;
    1556               3 :                 for(int i=0;i<poRing0->getNumPoints();i++)
    1557                 :                 {
    1558               3 :                     if (poRing0->getX(i) != poRing1->getX(i))
    1559                 :                     {
    1560               3 :                         bSameRing = FALSE;
    1561               3 :                         break;
    1562                 :                     }
    1563               0 :                     if (poRing0->getY(i) != poRing1->getY(i))
    1564                 :                     {
    1565               0 :                         bSameRing = FALSE;
    1566               0 :                         break;
    1567                 :                     }
    1568                 :                 }
    1569                 : 
    1570                 :                 /* Just keep on ring if they are identical */
    1571               3 :                 if (bSameRing)
    1572                 :                 {
    1573               0 :                     delete papoPoly[1];
    1574               0 :                     nPolys = 1;
    1575                 :                 }
    1576                 :             }
    1577                 :         }
    1578             227 :         if (nPolys)
    1579                 :         {
    1580                 :             poGeom = OGRGeometryFactory::organizePolygons(
    1581             134 :                     papoPoly, nPolys, &bIsValidGeometry, NULL);
    1582                 :         }
    1583             227 :         CPLFree(papoPoly);
    1584                 :     }
    1585                 : 
    1586             421 :     return poGeom;
    1587                 : }
    1588                 : 
    1589                 : /************************************************************************/
    1590                 : /*                          ExploreContents()                           */
    1591                 : /************************************************************************/
    1592                 : 
    1593               7 : void OGRPDFDataSource::ExploreContents(GDALPDFObject* poObj,
    1594                 :                                        GDALPDFObject* poResources)
    1595                 : {
    1596               7 :     std::map<CPLString, OGRPDFLayer*> oMapPropertyToLayer;
    1597                 : 
    1598               7 :     if (poObj->GetType() == PDFObjectType_Array)
    1599                 :     {
    1600               1 :         GDALPDFArray* poArray = poObj->GetArray();
    1601               4 :         for(int i=0;i<poArray->GetLength();i++)
    1602               3 :             ExploreContents(poArray->Get(i), poResources);
    1603                 :     }
    1604                 : 
    1605               7 :     if (poObj->GetType() != PDFObjectType_Dictionary)
    1606                 :         return;
    1607                 : 
    1608               6 :     GDALPDFStream* poStream = poObj->GetStream();
    1609               6 :     if (!poStream)
    1610                 :         return;
    1611                 : 
    1612               6 :     char* pszStr = poStream->GetBytes();
    1613               6 :     if (!pszStr)
    1614                 :         return;
    1615                 : 
    1616               6 :     const char* pszMCID = (const char*) pszStr;
    1617             405 :     while((pszMCID = strstr(pszMCID, "/MCID")) != NULL)
    1618                 :     {
    1619             393 :         const char* pszBDC = strstr(pszMCID, "BDC");
    1620             393 :         if (pszBDC)
    1621                 :         {
    1622                 :             /* Hack for http://www.avenza.com/sites/default/files/spatialpdf/US_County_Populations.pdf */
    1623                 :             /* FIXME: that logic is too fragile. */
    1624             393 :             const char* pszStartParsing = pszBDC;
    1625             393 :             const char* pszAfterBDC = pszBDC + 3;
    1626             393 :             int bMatchQ = FALSE;
    1627            1179 :             while (pszAfterBDC[0] == ' ' || pszAfterBDC[0] == '\r' || pszAfterBDC[0] == '\n')
    1628             393 :                 pszAfterBDC ++;
    1629             393 :             if (strncmp(pszAfterBDC, "0 0 m", 5) == 0)
    1630                 :             {
    1631               0 :                 const char* pszLastq = pszBDC;
    1632               0 :                 while(pszLastq > pszStr && *pszLastq != 'q')
    1633               0 :                     pszLastq --;
    1634                 : 
    1635               0 :                 if (pszLastq > pszStr && *pszLastq == 'q' &&
    1636               0 :                     (pszLastq[-1] == ' ' || pszLastq[-1] == '\r' || pszLastq[-1] == '\n') &&
    1637               0 :                     (pszLastq[1] == ' ' || pszLastq[1] == '\r' || pszLastq[1] == '\n'))
    1638                 :                 {
    1639               0 :                     pszStartParsing = pszLastq;
    1640               0 :                     bMatchQ = TRUE;
    1641                 :                 }
    1642                 :             }
    1643                 : 
    1644             393 :             int nMCID = atoi(pszMCID + 6);
    1645             393 :             if (GetGeometryFromMCID(nMCID) == NULL)
    1646                 :             {
    1647                 :                 OGRGeometry* poGeom = ParseContent(pszStartParsing, poResources,
    1648             391 :                                                    !bMatchQ, bMatchQ, oMapPropertyToLayer, NULL);
    1649             391 :                 if( poGeom != NULL )
    1650                 :                 {
    1651                 :                     /* Save geometry in map */
    1652             391 :                     oMapMCID[nMCID] = poGeom;
    1653                 :                 }
    1654                 :             }
    1655                 :         }
    1656             393 :         pszMCID += 5;
    1657                 :     }
    1658               6 :     CPLFree(pszStr);
    1659                 : }
    1660                 : 
    1661                 : /************************************************************************/
    1662                 : /*                           PDFSanitizeLayerName()                     */
    1663                 : /************************************************************************/
    1664                 : 
    1665                 : static
    1666               4 : CPLString PDFSanitizeLayerName(const char* pszName)
    1667                 : {
    1668               4 :     CPLString osName;
    1669              46 :     for(int i=0; pszName[i] != '\0'; i++)
    1670                 :     {
    1671              43 :         if (pszName[i] == ' ' || pszName[i] == '.' || pszName[i] == ',')
    1672               1 :             osName += "_";
    1673                 :         else
    1674              41 :             osName += pszName[i];
    1675                 :     }
    1676               0 :     return osName;
    1677                 : }
    1678                 : 
    1679                 : /************************************************************************/
    1680                 : /*                   ExploreContentsNonStructured()                     */
    1681                 : /************************************************************************/
    1682                 : 
    1683               2 : void OGRPDFDataSource::ExploreContentsNonStructuredInternal(GDALPDFObject* poContents,
    1684                 :                                                             GDALPDFObject* poResources,
    1685                 :                                                             std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer)
    1686                 : {
    1687               2 :     if (poContents->GetType() == PDFObjectType_Array)
    1688                 :     {
    1689               0 :         GDALPDFArray* poArray = poContents->GetArray();
    1690               0 :         char* pszConcatStr = NULL;
    1691               0 :         int nConcatLen = 0;
    1692               0 :         for(int i=0;i<poArray->GetLength();i++)
    1693                 :         {
    1694               0 :             GDALPDFObject* poObj = poArray->Get(i);
    1695               0 :             if( poObj->GetType() != PDFObjectType_Dictionary)
    1696               0 :                 break;
    1697               0 :             GDALPDFStream* poStream = poObj->GetStream();
    1698               0 :             if (!poStream)
    1699               0 :                 break;
    1700               0 :             char* pszStr = poStream->GetBytes();
    1701               0 :             if (!pszStr)
    1702               0 :                 break;
    1703               0 :             int nLen = (int)strlen(pszStr);
    1704               0 :             char* pszConcatStrNew = (char*)CPLRealloc(pszConcatStr, nConcatLen + nLen + 1);
    1705               0 :             if( pszConcatStrNew == NULL )
    1706                 :             {
    1707               0 :                 CPLFree(pszStr);
    1708               0 :                 break;
    1709                 :             }
    1710               0 :             pszConcatStr = pszConcatStrNew;
    1711               0 :             memcpy(pszConcatStr + nConcatLen, pszStr, nLen+1);
    1712               0 :             nConcatLen += nLen;
    1713               0 :             CPLFree(pszStr);
    1714                 :         }
    1715               0 :         if( pszConcatStr )
    1716               0 :             ParseContent(pszConcatStr, poResources, FALSE, FALSE, oMapPropertyToLayer, NULL);
    1717               0 :         CPLFree(pszConcatStr);
    1718               0 :         return;
    1719                 :     }
    1720                 : 
    1721               2 :     if (poContents->GetType() != PDFObjectType_Dictionary)
    1722               0 :         return;
    1723                 : 
    1724               2 :     GDALPDFStream* poStream = poContents->GetStream();
    1725               2 :     if (!poStream)
    1726               0 :         return;
    1727                 : 
    1728               2 :     char* pszStr = poStream->GetBytes();
    1729               2 :     if( !pszStr )
    1730               0 :         return;
    1731               2 :     ParseContent(pszStr, poResources, FALSE, FALSE, oMapPropertyToLayer, NULL);
    1732               2 :     CPLFree(pszStr);
    1733                 : }
    1734                 : 
    1735               2 : void OGRPDFDataSource::ExploreContentsNonStructured(GDALPDFObject* poContents,
    1736                 :                                                     GDALPDFObject* poResources)
    1737                 : {
    1738               2 :     std::map<CPLString, OGRPDFLayer*> oMapPropertyToLayer;
    1739               4 :     if (poResources != NULL &&
    1740               2 :         poResources->GetType() == PDFObjectType_Dictionary)
    1741                 :     {
    1742                 :         GDALPDFObject* poProperties =
    1743               2 :             poResources->GetDictionary()->Get("Properties");
    1744               4 :         if (poProperties != NULL &&
    1745               2 :             poProperties->GetType() == PDFObjectType_Dictionary)
    1746                 :         {
    1747               2 :             CPLAssert(poGDAL_DS != NULL);
    1748               2 :             char** papszLayersWithRef = poGDAL_DS->GetMetadata("LAYERS_WITH_REF");
    1749               2 :             char** papszIter = papszLayersWithRef;
    1750               2 :             std::map< std::pair<int, int>, OGRPDFLayer *> oMapNumGenToLayer;
    1751               6 :             while(papszIter && *papszIter)
    1752                 :             {
    1753               4 :                 char** papszTokens = CSLTokenizeString(*papszIter);
    1754                 : 
    1755               4 :                 if( CSLCount(papszTokens) != 3 ) {
    1756               0 :                     CSLDestroy(papszTokens);
    1757               0 :                     CPLDebug("PDF", "Ignore '%s', unparsable.", *papszIter);
    1758               0 :                     papszIter ++;
    1759               0 :                     continue;
    1760                 :                 }
    1761                 : 
    1762               4 :                 const char* pszLayerName = papszTokens[0];
    1763               4 :                 int nNum = atoi(papszTokens[1]);
    1764               4 :                 int nGen = atoi(papszTokens[2]);
    1765                 : 
    1766               4 :                 CPLString osSanitizedName(PDFSanitizeLayerName(pszLayerName));
    1767                 : 
    1768               4 :                 OGRPDFLayer* poLayer = (OGRPDFLayer*) GetLayerByName(osSanitizedName.c_str());
    1769               4 :                 if (poLayer == NULL)
    1770                 :                 {
    1771               4 :                     const char* pszWKT = poGDAL_DS->GetProjectionRef();
    1772               4 :                     OGRSpatialReference* poSRS = NULL;
    1773               4 :                     if (pszWKT && pszWKT[0] != '\0')
    1774                 :                     {
    1775               4 :                         poSRS = new OGRSpatialReference();
    1776               4 :                         poSRS->importFromWkt((char**) &pszWKT);
    1777                 :                     }
    1778                 : 
    1779                 :                     poLayer =
    1780               4 :                         new OGRPDFLayer(this, osSanitizedName.c_str(), poSRS, wkbUnknown);
    1781               8 :                     delete poSRS;
    1782                 : 
    1783                 :                     papoLayers = (OGRLayer**)
    1784               4 :                         CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
    1785               4 :                     papoLayers[nLayers] = poLayer;
    1786               4 :                     nLayers ++;
    1787                 :                 }
    1788                 : 
    1789               4 :                 oMapNumGenToLayer[ std::pair<int,int>(nNum, nGen) ] = poLayer;
    1790                 : 
    1791               4 :                 CSLDestroy(papszTokens);
    1792               4 :                 papszIter ++;
    1793                 :             }
    1794                 : 
    1795                 :             std::map<CPLString, GDALPDFObject*>& oMap =
    1796               2 :                                     poProperties->GetDictionary()->GetValues();
    1797               2 :             std::map<CPLString, GDALPDFObject*>::iterator oIter = oMap.begin();
    1798               2 :             std::map<CPLString, GDALPDFObject*>::iterator oEnd = oMap.end();
    1799                 : 
    1800               6 :             for(; oIter != oEnd; ++oIter)
    1801                 :             {
    1802               4 :                 const char* pszKey = oIter->first.c_str();
    1803               4 :                 GDALPDFObject* poObj = oIter->second;
    1804               4 :                 if( poObj->GetRefNum() != 0 )
    1805                 :                 {
    1806                 :                     std::map< std::pair<int, int>, OGRPDFLayer *>::iterator
    1807                 :                         oIterNumGenToLayer = oMapNumGenToLayer.find(
    1808               4 :                             std::pair<int,int>(poObj->GetRefNum(), poObj->GetRefGen()) );
    1809               4 :                     if( oIterNumGenToLayer != oMapNumGenToLayer.end() )
    1810                 :                     {
    1811               4 :                         oMapPropertyToLayer[pszKey] = oIterNumGenToLayer->second;
    1812                 :                     }
    1813                 :                 }
    1814               2 :             }
    1815                 :         }
    1816                 :     }
    1817                 : 
    1818               2 :     if( nLayers == 0 )
    1819                 :         return;
    1820                 : 
    1821                 :     ExploreContentsNonStructuredInternal(poContents,
    1822                 :                                          poResources,
    1823               2 :                                          oMapPropertyToLayer);
    1824                 : 
    1825                 :     /* Remove empty layers */
    1826               2 :     int i = 0;
    1827               8 :     while(i < nLayers)
    1828                 :     {
    1829               4 :         if (papoLayers[i]->GetFeatureCount() == 0)
    1830                 :         {
    1831               2 :             delete papoLayers[i];
    1832               2 :             if (i < nLayers - 1)
    1833                 :             {
    1834                 :                 memmove(papoLayers + i, papoLayers + i + 1,
    1835               0 :                         (nLayers - 1 - i) * sizeof(OGRPDFLayer*));
    1836                 :             }
    1837               2 :             nLayers --;
    1838                 :         }
    1839                 :         else
    1840               2 :             i ++;
    1841               0 :     }
    1842                 : }
    1843                 : 
    1844                 : /************************************************************************/
    1845                 : /*                               Open()                                 */
    1846                 : /************************************************************************/
    1847                 : 
    1848               6 : int OGRPDFDataSource::Open( const char * pszName)
    1849                 : {
    1850               6 :     this->pszName = CPLStrdup(pszName);
    1851                 : 
    1852               6 :     poGDAL_DS = GDALPDFOpen(pszName, GA_ReadOnly);
    1853               6 :     if (poGDAL_DS == NULL)
    1854               0 :         return FALSE;
    1855                 : 
    1856               6 :     const char* pszPageObj = poGDAL_DS->GetMetadataItem("PDF_PAGE_OBJECT");
    1857               6 :     if (pszPageObj)
    1858               6 :         sscanf(pszPageObj, "%p", &poPageObj);
    1859               6 :     if (poPageObj == NULL || poPageObj->GetType() != PDFObjectType_Dictionary)
    1860               0 :         return FALSE;
    1861                 : 
    1862               6 :     GDALPDFObject* poMediaBox = poPageObj->GetDictionary()->Get("MediaBox");
    1863              18 :     if (poMediaBox == NULL || poMediaBox->GetType() != PDFObjectType_Array ||
    1864              12 :         poMediaBox->GetArray()->GetLength() != 4)
    1865               0 :         return FALSE;
    1866                 : 
    1867               6 :     if (poMediaBox->GetArray()->Get(2)->GetType() == PDFObjectType_Real)
    1868               1 :         dfPageWidth = poMediaBox->GetArray()->Get(2)->GetReal();
    1869               5 :     else if (poMediaBox->GetArray()->Get(2)->GetType() == PDFObjectType_Int)
    1870               5 :         dfPageWidth = poMediaBox->GetArray()->Get(2)->GetInt();
    1871                 :     else
    1872               0 :         return FALSE;
    1873                 : 
    1874               6 :     if (poMediaBox->GetArray()->Get(3)->GetType() == PDFObjectType_Real)
    1875               1 :         dfPageHeight = poMediaBox->GetArray()->Get(3)->GetReal();
    1876               5 :     else if (poMediaBox->GetArray()->Get(3)->GetType() == PDFObjectType_Int)
    1877               5 :         dfPageHeight = poMediaBox->GetArray()->Get(3)->GetInt();
    1878                 :     else
    1879               0 :         return FALSE;
    1880                 : 
    1881               6 :     GDALPDFObject* poContents = poPageObj->GetDictionary()->Get("Contents");
    1882               6 :     if (poContents == NULL)
    1883               0 :         return FALSE;
    1884                 : 
    1885               7 :     if (poContents->GetType() != PDFObjectType_Dictionary &&
    1886               1 :         poContents->GetType() != PDFObjectType_Array)
    1887               0 :         return FALSE;
    1888                 : 
    1889               6 :     GDALPDFObject* poResources = poPageObj->GetDictionary()->Get("Resources");
    1890               6 :     if (poResources == NULL || poResources->GetType() != PDFObjectType_Dictionary)
    1891               0 :         return FALSE;
    1892                 :     
    1893               6 :     const char* pszCatalog = poGDAL_DS->GetMetadataItem("PDF_CATALOG_OBJECT");
    1894               6 :     if (pszCatalog)
    1895               6 :         sscanf(pszCatalog, "%p", &poCatalogObj);
    1896               6 :     if (poCatalogObj == NULL || poCatalogObj->GetType() != PDFObjectType_Dictionary)
    1897               0 :         return FALSE;
    1898                 : 
    1899               6 :     nXSize = poGDAL_DS->GetRasterXSize();
    1900               6 :     nYSize = poGDAL_DS->GetRasterYSize();
    1901               6 :     poGDAL_DS->GetGeoTransform(adfGeoTransform);
    1902                 : 
    1903                 : 
    1904               6 :     GDALPDFObject* poStructTreeRoot = poCatalogObj->GetDictionary()->Get("StructTreeRoot");
    1905              10 :     if (CSLTestBoolean(CPLGetConfigOption("OGR_PDF_READ_NON_STRUCTURED", "NO")) ||
    1906                 :         poStructTreeRoot == NULL ||
    1907               4 :         poStructTreeRoot->GetType() != PDFObjectType_Dictionary)
    1908                 :     {
    1909               2 :         ExploreContentsNonStructured(poContents, poResources);
    1910                 :     }
    1911                 :     else
    1912                 :     {
    1913               4 :         ExploreContents(poContents, poResources);
    1914               4 :         ExploreTree(poStructTreeRoot, 0);
    1915                 :     }
    1916                 : 
    1917               6 :     CleanupIntermediateResources();
    1918                 : 
    1919               6 :     int bEmptyDS = TRUE;
    1920               6 :     for(int i=0;i<nLayers;i++)
    1921                 :     {
    1922               6 :         if (papoLayers[i]->GetFeatureCount() != 0)
    1923                 :         {
    1924               6 :             bEmptyDS = FALSE;
    1925               6 :             break;
    1926                 :         }
    1927                 :     }
    1928               6 :     if (bEmptyDS)
    1929               0 :         return FALSE;
    1930                 : 
    1931               6 :     return TRUE;
    1932                 : }
    1933                 : 
    1934                 : /************************************************************************/
    1935                 : /*                               Create()                               */
    1936                 : /************************************************************************/
    1937                 : 
    1938               2 : int OGRPDFDataSource::Create( const char * pszName, char **papszOptions )
    1939                 : {
    1940               2 :     this->pszName = CPLStrdup(pszName);
    1941               2 :     this->papszOptions = CSLDuplicate(papszOptions);
    1942               2 :     bWritable = TRUE;
    1943                 : 
    1944               2 :     return TRUE;
    1945                 : }
    1946                 : 
    1947                 : /************************************************************************/
    1948                 : /*                            CreateLayer()                             */
    1949                 : /************************************************************************/
    1950                 : 
    1951                 : OGRLayer *
    1952               2 : OGRPDFDataSource::CreateLayer( const char * pszLayerName,
    1953                 :                                 OGRSpatialReference *poSRS,
    1954                 :                                 OGRwkbGeometryType eType,
    1955                 :                                 char ** papszOptions )
    1956                 : 
    1957                 : {
    1958                 : /* -------------------------------------------------------------------- */
    1959                 : /*      Create the layer object.                                        */
    1960                 : /* -------------------------------------------------------------------- */
    1961               2 :     OGRLayer* poLayer = new OGRPDFLayer(this, pszLayerName, poSRS, eType);
    1962                 : 
    1963               2 :     papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
    1964               2 :     papoLayers[nLayers] = poLayer;
    1965               2 :     nLayers ++;
    1966                 : 
    1967               2 :     return poLayer;
    1968                 : }
    1969                 : 
    1970                 : /************************************************************************/
    1971                 : /*                            SyncToDisk()                              */
    1972                 : /************************************************************************/
    1973                 : 
    1974               8 : OGRErr OGRPDFDataSource::SyncToDisk()
    1975                 : {
    1976               8 :     if (nLayers == 0 || !bModified || !bWritable)
    1977               6 :         return OGRERR_NONE;
    1978                 : 
    1979               2 :     bModified = FALSE;
    1980                 : 
    1981               2 :     OGREnvelope sGlobalExtent;
    1982               2 :     int bHasExtent = FALSE;
    1983               4 :     for(int i=0;i<nLayers;i++)
    1984                 :     {
    1985               2 :         OGREnvelope sExtent;
    1986               2 :         if (papoLayers[i]->GetExtent(&sExtent) == OGRERR_NONE)
    1987                 :         {
    1988               2 :             bHasExtent = TRUE;
    1989               2 :             sGlobalExtent.Merge(sExtent);
    1990                 :         }
    1991                 :     }
    1992               2 :     if (!bHasExtent ||
    1993                 :         sGlobalExtent.MinX == sGlobalExtent.MaxX ||
    1994                 :         sGlobalExtent.MinY == sGlobalExtent.MaxY)
    1995                 :     {
    1996                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1997               0 :                  "Cannot compute spatial extent of features");
    1998               0 :         return OGRERR_FAILURE;
    1999                 :     }
    2000                 : 
    2001               2 :     PDFCompressMethod eStreamCompressMethod = COMPRESS_DEFLATE;
    2002               2 :     const char* pszStreamCompressMethod = CSLFetchNameValue(papszOptions, "STREAM_COMPRESS");
    2003               2 :     if (pszStreamCompressMethod)
    2004                 :     {
    2005               0 :         if( EQUAL(pszStreamCompressMethod, "NONE") )
    2006               0 :             eStreamCompressMethod = COMPRESS_NONE;
    2007               0 :         else if( EQUAL(pszStreamCompressMethod, "DEFLATE") )
    2008               0 :             eStreamCompressMethod = COMPRESS_DEFLATE;
    2009                 :         else
    2010                 :         {
    2011                 :             CPLError( CE_Warning, CPLE_NotSupported,
    2012               0 :                     "Unsupported value for STREAM_COMPRESS.");
    2013                 :         }
    2014                 :     }
    2015                 : 
    2016                 :     const char* pszGEO_ENCODING =
    2017               2 :         CSLFetchNameValueDef(papszOptions, "GEO_ENCODING", "ISO32000");
    2018                 : 
    2019               2 :     double dfDPI = atof(CSLFetchNameValueDef(papszOptions, "DPI", "72"));
    2020               2 :     if (dfDPI < 72.0)
    2021               0 :         dfDPI = 72.0;
    2022                 : 
    2023               2 :     const char* pszNEATLINE = CSLFetchNameValue(papszOptions, "NEATLINE");
    2024                 : 
    2025               2 :     int nMargin = atoi(CSLFetchNameValueDef(papszOptions, "MARGIN", "0"));
    2026                 : 
    2027                 :     PDFMargins sMargins;
    2028               2 :     sMargins.nLeft = nMargin;
    2029               2 :     sMargins.nRight = nMargin;
    2030               2 :     sMargins.nTop = nMargin;
    2031               2 :     sMargins.nBottom = nMargin;
    2032                 : 
    2033               2 :     const char* pszLeftMargin = CSLFetchNameValue(papszOptions, "LEFT_MARGIN");
    2034               2 :     if (pszLeftMargin) sMargins.nLeft = atoi(pszLeftMargin);
    2035                 : 
    2036               2 :     const char* pszRightMargin = CSLFetchNameValue(papszOptions, "RIGHT_MARGIN");
    2037               2 :     if (pszRightMargin) sMargins.nRight = atoi(pszRightMargin);
    2038                 : 
    2039               2 :     const char* pszTopMargin = CSLFetchNameValue(papszOptions, "TOP_MARGIN");
    2040               2 :     if (pszTopMargin) sMargins.nTop = atoi(pszTopMargin);
    2041                 : 
    2042               2 :     const char* pszBottomMargin = CSLFetchNameValue(papszOptions, "BOTTOM_MARGIN");
    2043               2 :     if (pszBottomMargin) sMargins.nBottom = atoi(pszBottomMargin);
    2044                 : 
    2045               2 :     const char* pszExtraImages = CSLFetchNameValue(papszOptions, "EXTRA_IMAGES");
    2046               2 :     const char* pszExtraStream = CSLFetchNameValue(papszOptions, "EXTRA_STREAM");
    2047               2 :     const char* pszExtraLayerName = CSLFetchNameValue(papszOptions, "EXTRA_LAYER_NAME");
    2048                 : 
    2049               2 :     const char* pszOGRDisplayField = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_FIELD");
    2050               2 :     const char* pszOGRDisplayLayerNames = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_LAYER_NAMES");
    2051               2 :     int bWriteOGRAttributes = CSLFetchBoolean(papszOptions, "OGR_WRITE_ATTRIBUTES", TRUE);
    2052               2 :     const char* pszOGRLinkField = CSLFetchNameValue(papszOptions, "OGR_LINK_FIELD");
    2053                 : 
    2054               2 :     const char* pszOffLayers = CSLFetchNameValue(papszOptions, "OFF_LAYERS");
    2055               2 :     const char* pszExclusiveLayers = CSLFetchNameValue(papszOptions, "EXCLUSIVE_LAYERS");
    2056                 : 
    2057               2 :     const char* pszJavascript = CSLFetchNameValue(papszOptions, "JAVASCRIPT");
    2058               2 :     const char* pszJavascriptFile = CSLFetchNameValue(papszOptions, "JAVASCRIPT_FILE");
    2059                 : 
    2060                 : /* -------------------------------------------------------------------- */
    2061                 : /*      Create file.                                                    */
    2062                 : /* -------------------------------------------------------------------- */
    2063               2 :     VSILFILE* fp = VSIFOpenL(pszName, "wb");
    2064               2 :     if( fp == NULL )
    2065                 :     {
    2066                 :         CPLError( CE_Failure, CPLE_OpenFailed,
    2067                 :                   "Unable to create PDF file %s.\n",
    2068               0 :                   pszName );
    2069               0 :         return OGRERR_FAILURE;
    2070                 :     }
    2071                 : 
    2072               2 :     GDALPDFWriter oWriter(fp);
    2073                 : 
    2074               2 :     double dfRatio = (sGlobalExtent.MaxY - sGlobalExtent.MinY) / (sGlobalExtent.MaxX - sGlobalExtent.MinX);
    2075                 : 
    2076                 :     int nWidth, nHeight;
    2077                 : 
    2078               2 :     if (dfRatio < 1)
    2079                 :     {
    2080               0 :         nWidth = 1024;
    2081               0 :         nHeight = nWidth * dfRatio;
    2082                 :     }
    2083                 :     else
    2084                 :     {
    2085               2 :         nHeight = 1024;
    2086               2 :         nWidth = nHeight / dfRatio;
    2087                 :     }
    2088                 : 
    2089               2 :     GDALDataset* poSrcDS = MEMDataset::Create( "MEM:::", nWidth, nHeight, 0, GDT_Byte, NULL );
    2090                 : 
    2091                 :     double adfGeoTransform[6];
    2092               2 :     adfGeoTransform[0] = sGlobalExtent.MinX;
    2093               2 :     adfGeoTransform[1] = (sGlobalExtent.MaxX - sGlobalExtent.MinX) / nWidth;
    2094               2 :     adfGeoTransform[2] = 0;
    2095               2 :     adfGeoTransform[3] = sGlobalExtent.MaxY;
    2096               2 :     adfGeoTransform[4] = 0;
    2097               2 :     adfGeoTransform[5] = - (sGlobalExtent.MaxY - sGlobalExtent.MinY) / nHeight;
    2098                 : 
    2099               2 :     poSrcDS->SetGeoTransform(adfGeoTransform);
    2100                 : 
    2101               2 :     OGRSpatialReference* poSRS = papoLayers[0]->GetSpatialRef();
    2102               2 :     if (poSRS)
    2103                 :     {
    2104               2 :         char* pszWKT = NULL;
    2105               2 :         poSRS->exportToWkt(&pszWKT);
    2106               2 :         poSrcDS->SetProjection(pszWKT);
    2107               2 :         CPLFree(pszWKT);
    2108                 :     }
    2109                 : 
    2110               2 :     oWriter.SetInfo(poSrcDS, papszOptions);
    2111                 : 
    2112                 :     oWriter.StartPage(poSrcDS,
    2113                 :                       dfDPI,
    2114                 :                       pszGEO_ENCODING,
    2115                 :                       pszNEATLINE,
    2116                 :                       &sMargins,
    2117                 :                       eStreamCompressMethod,
    2118               2 :                       bWriteOGRAttributes);
    2119                 : 
    2120               2 :     int iObj = 0;
    2121                 :     
    2122               2 :     char** papszLayerNames = CSLTokenizeString2(pszOGRDisplayLayerNames,",",0);
    2123                 : 
    2124               4 :     for(int i=0;i<nLayers;i++)
    2125                 :     {
    2126               2 :         CPLString osLayerName;
    2127               2 :         if (CSLCount(papszLayerNames) < nLayers)
    2128               2 :             osLayerName = papoLayers[i]->GetName();
    2129                 :         else
    2130               0 :             osLayerName = papszLayerNames[i];
    2131                 : 
    2132                 :         oWriter.WriteOGRLayer((OGRDataSourceH)this,
    2133                 :                               i,
    2134                 :                               pszOGRDisplayField,
    2135                 :                               pszOGRLinkField,
    2136                 :                               osLayerName,
    2137                 :                               bWriteOGRAttributes,
    2138               2 :                               iObj);
    2139                 :     }
    2140                 : 
    2141               2 :     CSLDestroy(papszLayerNames);
    2142                 : 
    2143                 :     oWriter.EndPage(pszExtraImages,
    2144                 :                     pszExtraStream,
    2145                 :                     pszExtraLayerName,
    2146                 :                     pszOffLayers,
    2147               2 :                     pszExclusiveLayers);
    2148                 : 
    2149               2 :     if (pszJavascript)
    2150               0 :         oWriter.WriteJavascript(pszJavascript);
    2151               2 :     else if (pszJavascriptFile)
    2152               0 :         oWriter.WriteJavascriptFile(pszJavascriptFile);
    2153                 : 
    2154               2 :     oWriter.Close();
    2155                 : 
    2156               2 :     delete poSrcDS;
    2157                 : 
    2158               2 :     return OGRERR_NONE;
    2159                 : }

Generated by: LCOV version 1.7