LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/pdf - ogrpdfdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 676 561 83.0 %
Date: 2012-04-28 Functions: 29 22 75.9 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrpdfdatasource.cpp 24195 2012-04-02 20:05:33Z 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                 : CPL_CVSID("$Id: ogrpdfdatasource.cpp 24195 2012-04-02 20:05:33Z rouault $");
      40                 : 
      41                 : /************************************************************************/
      42                 : /*                            OGRPDFLayer()                             */
      43                 : /************************************************************************/
      44                 : 
      45              26 : OGRPDFLayer::OGRPDFLayer( OGRPDFDataSource* poDS,
      46                 :                           const char * pszName,
      47                 :                           OGRSpatialReference *poSRS,
      48                 :                           OGRwkbGeometryType eGeomType ) :
      49              26 :                                 OGRMemLayer(pszName, poSRS, eGeomType )
      50                 : {
      51              26 :     this->poDS = poDS;
      52              26 : }
      53                 : 
      54                 : /************************************************************************/
      55                 : /*                            CreateFeature()                           */
      56                 : /************************************************************************/
      57                 : 
      58             752 : OGRErr OGRPDFLayer::CreateFeature( OGRFeature *poFeature )
      59                 : {
      60             752 :     poDS->SetModified();
      61             752 :     return OGRMemLayer::CreateFeature(poFeature);
      62                 : }
      63                 : 
      64                 : /************************************************************************/
      65                 : /*                              Fill()                                  */
      66                 : /************************************************************************/
      67                 : 
      68              24 : void OGRPDFLayer::Fill( GDALPDFArray* poArray )
      69                 : {
      70              24 :     OGRwkbGeometryType eGeomType = wkbUnknown;
      71              24 :     int bGeomTypeSet = FALSE;
      72              24 :     int bGeomTypeMixed = FALSE;
      73                 : 
      74             768 :     for(int i=0;i<poArray->GetLength();i++)
      75                 :     {
      76             744 :         GDALPDFObject* poFeatureObj = poArray->Get(i);
      77             744 :         if (poFeatureObj->GetType() != PDFObjectType_Dictionary)
      78               0 :             continue;
      79                 : 
      80             744 :         GDALPDFObject* poA = poFeatureObj->GetDictionary()->Get("A");
      81             744 :         if (!(poA != NULL && poA->GetType() == PDFObjectType_Dictionary))
      82               0 :             continue;
      83                 : 
      84             744 :         GDALPDFObject* poP = poA->GetDictionary()->Get("P");
      85             744 :         if (!(poP != NULL && poP->GetType() == PDFObjectType_Array))
      86               0 :             continue;
      87                 : 
      88             744 :         GDALPDFObject* poK = poFeatureObj->GetDictionary()->Get("K");
      89             744 :         int nK = -1;
      90             744 :         if (poK != NULL && poK->GetType() == PDFObjectType_Int)
      91             744 :             nK = poK->GetInt();
      92                 : 
      93             744 :         GDALPDFArray* poPArray = poP->GetArray();
      94                 :         int j;
      95            2776 :         for(j = 0;j<poPArray->GetLength();j++)
      96                 :         {
      97            2032 :             GDALPDFObject* poKV = poPArray->Get(j);
      98            2032 :             if (poKV->GetType() == PDFObjectType_Dictionary)
      99                 :             {
     100            2032 :                 GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
     101            2032 :                 GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
     102            2032 :                 if (poN != NULL && poN->GetType() == PDFObjectType_String &&
     103                 :                     poV != NULL)
     104                 :                 {
     105            2032 :                     int nIdx = GetLayerDefn()->GetFieldIndex( poN->GetString().c_str() );
     106            2032 :                     OGRFieldType eType = OFTString;
     107            2032 :                     if (poV->GetType() == PDFObjectType_Int)
     108               2 :                         eType = OFTInteger;
     109            2030 :                     else if (poV->GetType() == PDFObjectType_Real)
     110               2 :                         eType = OFTReal;
     111            2032 :                     if (nIdx < 0)
     112                 :                     {
     113              84 :                         OGRFieldDefn oField(poN->GetString().c_str(), eType);
     114              84 :                         CreateField(&oField);
     115                 :                     }
     116            1948 :                     else if (GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != eType &&
     117               0 :                                 GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != OFTString)
     118                 :                     {
     119               0 :                         OGRFieldDefn oField(poN->GetString().c_str(), OFTString);
     120               0 :                         AlterFieldDefn( nIdx, &oField, ALTER_TYPE_FLAG );
     121                 :                     }
     122                 :                 }
     123                 :             }
     124                 :         }
     125                 : 
     126             744 :         OGRFeature* poFeature = new OGRFeature(GetLayerDefn());
     127            2776 :         for(j = 0;j<poPArray->GetLength();j++)
     128                 :         {
     129            2032 :             GDALPDFObject* poKV = poPArray->Get(j);
     130            2032 :             if (poKV->GetType() == PDFObjectType_Dictionary)
     131                 :             {
     132            2032 :                 GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
     133            2032 :                 GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
     134            2032 :                 if (poN != NULL && poN->GetType() == PDFObjectType_String &&
     135                 :                     poV != NULL)
     136                 :                 {
     137            2032 :                     if (poV->GetType() == PDFObjectType_String)
     138            2028 :                         poFeature->SetField(poN->GetString().c_str(), poV->GetString().c_str());
     139               4 :                     else if (poV->GetType() == PDFObjectType_Int)
     140               2 :                         poFeature->SetField(poN->GetString().c_str(), poV->GetInt());
     141               2 :                     else if (poV->GetType() == PDFObjectType_Real)
     142               2 :                         poFeature->SetField(poN->GetString().c_str(), poV->GetReal());
     143                 :                 }
     144                 :             }
     145                 :         }
     146                 : 
     147             744 :         if (nK >= 0)
     148                 :         {
     149             744 :             OGRGeometry* poGeom = poDS->GetGeometryFromMCID(nK);
     150             744 :             if (poGeom)
     151                 :             {
     152             744 :                 if (!bGeomTypeSet)
     153                 :                 {
     154              24 :                     bGeomTypeSet = TRUE;
     155              24 :                     eGeomType = poGeom->getGeometryType();
     156                 :                 }
     157             720 :                 else if (eGeomType != poGeom->getGeometryType())
     158                 :                 {
     159              16 :                     bGeomTypeMixed = TRUE;
     160                 :                 }
     161             744 :                 poGeom->assignSpatialReference(GetSpatialRef());
     162             744 :                 poFeature->SetGeometry(poGeom);
     163                 :             }
     164                 :         }
     165                 : 
     166             744 :         CreateFeature(poFeature);
     167                 : 
     168             744 :         delete poFeature;
     169                 :     }
     170                 : 
     171              24 :     if (bGeomTypeSet && !bGeomTypeMixed)
     172              20 :         GetLayerDefn()->SetGeomType(eGeomType);
     173              24 : }
     174                 : 
     175                 : /************************************************************************/
     176                 : /*                           TestCapability()                           */
     177                 : /************************************************************************/
     178                 : 
     179               0 : int OGRPDFLayer::TestCapability( const char * pszCap )
     180                 : 
     181                 : {
     182               0 :     if( EQUAL(pszCap,OLCStringsAsUTF8) )
     183               0 :         return TRUE;
     184                 :     else
     185               0 :         return OGRMemLayer::TestCapability(pszCap);
     186                 : }
     187                 : 
     188                 : /************************************************************************/
     189                 : /*                          OGRPDFDataSource()                          */
     190                 : /************************************************************************/
     191                 : 
     192               6 : OGRPDFDataSource::OGRPDFDataSource()
     193                 : 
     194                 : {
     195               6 :     pszName = NULL;
     196               6 :     papszOptions = NULL;
     197                 : 
     198               6 :     nLayers = 0;
     199               6 :     papoLayers = NULL;
     200                 : 
     201               6 :     bModified = FALSE;
     202               6 :     bWritable = FALSE;
     203                 : 
     204               6 :     poGDAL_DS = NULL;
     205               6 :     poPageObj = NULL;
     206               6 :     poCatalogObj = NULL;
     207               6 :     dfPageWidth = dfPageHeight = 0;
     208                 : 
     209               6 :     InitMapOperators();
     210               6 : }
     211                 : 
     212                 : /************************************************************************/
     213                 : /*                         ~OGRPDFDataSource()                          */
     214                 : /************************************************************************/
     215                 : 
     216               6 : OGRPDFDataSource::~OGRPDFDataSource()
     217                 : 
     218                 : {
     219               6 :     SyncToDisk();
     220                 : 
     221               6 :     CleanupIntermediateResources();
     222                 : 
     223               6 :     CPLFree( pszName );
     224               6 :     CSLDestroy( papszOptions );
     225                 : 
     226              32 :     for(int i=0;i<nLayers;i++)
     227              26 :         delete papoLayers[i];
     228               6 :     CPLFree( papoLayers );
     229               6 : }
     230                 : 
     231                 : /************************************************************************/
     232                 : /*                   CleanupIntermediateResources()                     */
     233                 : /************************************************************************/
     234                 : 
     235              10 : void OGRPDFDataSource::CleanupIntermediateResources()
     236                 : {
     237              10 :     std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.begin();
     238             754 :     for( ; oMapIter != oMapMCID.end(); ++oMapIter)
     239             744 :         delete oMapIter->second;
     240              10 :     oMapMCID.erase(oMapMCID.begin(), oMapMCID.end());
     241                 : 
     242              10 :     delete poGDAL_DS;
     243              10 :     poGDAL_DS = NULL;
     244                 : 
     245              10 :     poPageObj = NULL;
     246              10 :     poCatalogObj = NULL;
     247              10 : }
     248                 : 
     249                 : /************************************************************************/
     250                 : /*                          InitMapOperators()                          */
     251                 : /************************************************************************/
     252                 : 
     253               6 : void OGRPDFDataSource::InitMapOperators()
     254                 : {
     255               6 :     oMapOperators["b"] = 0;
     256              12 :     oMapOperators["B"] = 0;
     257              12 :     oMapOperators["b*"] = 0;
     258              12 :     oMapOperators["B*"] = 0;
     259              12 :     oMapOperators["BDC"] = 2;
     260                 :     // BI
     261                 :     // BMC
     262                 :     // BT
     263                 :     // BX
     264              12 :     oMapOperators["c"] = 6;
     265              12 :     oMapOperators["cm"] = 6;
     266              12 :     oMapOperators["CS"] = 1;
     267              12 :     oMapOperators["cs"] = 1;
     268              12 :     oMapOperators["d"] = 1; /* we have ignored the first arg */
     269                 :     // d0
     270                 :     // d1
     271              12 :     oMapOperators["Do"] = 1;
     272                 :     // DP
     273                 :     // EI
     274              12 :     oMapOperators["EMC"] = 0;
     275                 :     // ET
     276                 :     // EX
     277              12 :     oMapOperators["f"] = 0;
     278              12 :     oMapOperators["F"] = 0;
     279              12 :     oMapOperators["f*"] = 0;
     280              12 :     oMapOperators["G"] = 1;
     281              12 :     oMapOperators["g"] = 1;
     282              12 :     oMapOperators["gs"] = 1;
     283              12 :     oMapOperators["h"] = 0;
     284              12 :     oMapOperators["i"] = 1;
     285                 :     // ID
     286              12 :     oMapOperators["j"] = 1;
     287              12 :     oMapOperators["J"] = 1;
     288                 :     // K
     289                 :     // k
     290              12 :     oMapOperators["l"] = 2;
     291              12 :     oMapOperators["m"] = 2;
     292              12 :     oMapOperators["M"] = 1;
     293                 :     // MP
     294              12 :     oMapOperators["n"] = 0;
     295              12 :     oMapOperators["q"] = 0;
     296              12 :     oMapOperators["Q"] = 0;
     297              12 :     oMapOperators["re"] = 4;
     298              12 :     oMapOperators["RG"] = 3;
     299              12 :     oMapOperators["rg"] = 3;
     300                 :     // ri
     301              12 :     oMapOperators["s"] = 0;
     302              12 :     oMapOperators["S"] = 0;
     303                 :     // SC
     304                 :     // sc
     305              12 :     oMapOperators["SCN"] = -1;
     306              12 :     oMapOperators["scn"] = -1;
     307                 :     // sh
     308                 :     // T*
     309                 :     // Tc
     310                 :     // Td
     311                 :     // TD
     312                 :     // Tf
     313                 :     // Tj
     314                 :     // TJ
     315                 :     // TL
     316                 :     // Tm
     317                 :     // Tr
     318                 :     // Ts
     319                 :     // Tw
     320                 :     // Tz
     321              12 :     oMapOperators["v"] = 4;
     322              12 :     oMapOperators["w"] = 1;
     323              12 :     oMapOperators["W"] = 0;
     324              12 :     oMapOperators["W*"] = 0;
     325              12 :     oMapOperators["y"] = 4;
     326                 :     // '
     327                 :     // "
     328               6 : }
     329                 : 
     330                 : /************************************************************************/
     331                 : /*                           TestCapability()                           */
     332                 : /************************************************************************/
     333                 : 
     334               0 : int OGRPDFDataSource::TestCapability( const char * pszCap )
     335                 : 
     336                 : {
     337               0 :     if( EQUAL(pszCap,ODsCCreateLayer) )
     338               0 :         return TRUE;
     339                 :     else
     340               0 :         return FALSE;
     341                 : }
     342                 : 
     343                 : /************************************************************************/
     344                 : /*                              GetLayer()                              */
     345                 : /************************************************************************/
     346                 : 
     347              58 : OGRLayer *OGRPDFDataSource::GetLayer( int iLayer )
     348                 : 
     349                 : {
     350              58 :     if (iLayer < 0 || iLayer >= nLayers)
     351               0 :         return NULL;
     352                 : 
     353              58 :     return papoLayers[iLayer];
     354                 : }
     355                 : 
     356                 : /************************************************************************/
     357                 : /*                            GetLayerCount()                           */
     358                 : /************************************************************************/
     359                 : 
     360              18 : int OGRPDFDataSource::GetLayerCount()
     361                 : {
     362              18 :     return nLayers;
     363                 : }
     364                 : 
     365                 : /************************************************************************/
     366                 : /*                            ExploreTree()                             */
     367                 : /************************************************************************/
     368                 : 
     369              54 : void OGRPDFDataSource::ExploreTree(GDALPDFObject* poObj)
     370                 : {
     371              54 :     if (poObj->GetType() != PDFObjectType_Dictionary)
     372               0 :         return;
     373                 : 
     374              54 :     GDALPDFDictionary* poDict = poObj->GetDictionary();
     375                 : 
     376              54 :     GDALPDFObject* poS = poDict->Get("S");
     377              54 :     CPLString osS;
     378              54 :     if (poS != NULL && poS->GetType() == PDFObjectType_Name)
     379                 :     {
     380              50 :         osS = poS->GetName();
     381                 :     }
     382                 : 
     383              54 :     GDALPDFObject* poT = poDict->Get("T");
     384              54 :     CPLString osT;
     385              54 :     if (poT != NULL && poT->GetType() == PDFObjectType_String)
     386                 :     {
     387              46 :         osT = poT->GetString();
     388                 :     }
     389                 : 
     390              54 :     GDALPDFObject* poK = poDict->Get("K");
     391              54 :     if (poK == NULL)
     392                 :         return;
     393                 : 
     394              54 :     if (poK->GetType() == PDFObjectType_Array)
     395                 :     {
     396              52 :         GDALPDFArray* poArray = poK->GetArray();
     397             520 :         if (poArray->GetLength() > 0 &&
     398             104 :             poArray->Get(0)->GetType() == PDFObjectType_Dictionary &&
     399             156 :             poArray->Get(0)->GetDictionary()->Get("K") != NULL &&
     400             208 :             poArray->Get(0)->GetDictionary()->Get("K")->GetType() == PDFObjectType_Int)
     401                 :         {
     402              24 :             CPLString osLayerName;
     403              24 :             if (osT.size())
     404              22 :                 osLayerName = osT;
     405                 :             else
     406                 :             {
     407               2 :                 if (osS.size())
     408               2 :                     osLayerName = osS;
     409                 :                 else
     410               0 :                     osLayerName = CPLSPrintf("Layer%d", nLayers + 1);
     411                 :             }
     412                 : 
     413              24 :             const char* pszWKT = poGDAL_DS->GetProjectionRef();
     414              24 :             OGRSpatialReference* poSRS = NULL;
     415              24 :             if (pszWKT && pszWKT[0] != '\0')
     416                 :             {
     417              24 :                 poSRS = new OGRSpatialReference();
     418              24 :                 poSRS->importFromWkt((char**) &pszWKT);
     419                 :             }
     420                 : 
     421                 :             OGRPDFLayer* poLayer =
     422              24 :                 new OGRPDFLayer(this, osLayerName.c_str(), poSRS, wkbUnknown);
     423              48 :             delete poSRS;
     424                 : 
     425              24 :             poLayer->Fill(poArray);
     426                 : 
     427                 :             papoLayers = (OGRLayer**)
     428              24 :                 CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
     429              24 :             papoLayers[nLayers] = poLayer;
     430              24 :             nLayers ++;
     431                 :         }
     432                 :         else
     433                 :         {
     434              76 :             for(int i=0;i<poArray->GetLength();i++)
     435              48 :                 ExploreTree(poArray->Get(i));
     436                 :         }
     437                 :     }
     438               2 :     else if (poK->GetType() == PDFObjectType_Dictionary)
     439                 :     {
     440               2 :         ExploreTree(poK);
     441               0 :     }
     442                 : }
     443                 : 
     444                 : /************************************************************************/
     445                 : /*                        GetGeometryFromMCID()                         */
     446                 : /************************************************************************/
     447                 : 
     448            1488 : OGRGeometry* OGRPDFDataSource::GetGeometryFromMCID(int nMCID)
     449                 : {
     450            1488 :     std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.find(nMCID);
     451            1488 :     if (oMapIter != oMapMCID.end())
     452             744 :         return oMapIter->second;
     453                 :     else
     454             744 :         return NULL;
     455                 : }
     456                 : 
     457                 : /************************************************************************/
     458                 : /*                            GraphicState                              */
     459                 : /************************************************************************/
     460                 : 
     461                 : class GraphicState
     462               8 : {
     463                 :     public:
     464                 :         double adfCM[6];
     465                 : 
     466             752 :         GraphicState()
     467                 :         {
     468             752 :             adfCM[0] = 1;
     469             752 :             adfCM[1] = 0;
     470             752 :             adfCM[2] = 0;
     471             752 :             adfCM[3] = 1;
     472             752 :             adfCM[4] = 0;
     473             752 :             adfCM[5] = 0;
     474             752 :         }
     475                 : 
     476               0 :         void MultiplyBy(double adfMatrix[6])
     477                 :         {
     478                 :             /*
     479                 :             [ a b 0 ]     [ a' b' 0]     [ aa' + bc'       ab' + bd'       0 ]
     480                 :             [ c d 0 ]  *  [ c' d' 0]  =  [ ca' + dc'       cb' + dd'       0 ]
     481                 :             [ e f 1 ]     [ e' f' 1]     [ ea' + fc' + e'  eb' + fd' + f'  1 ]
     482                 :             */
     483                 : 
     484               0 :             double a = adfCM[0];
     485               0 :             double b = adfCM[1];
     486               0 :             double c = adfCM[2];
     487               0 :             double d = adfCM[3];
     488               0 :             double e = adfCM[4];
     489               0 :             double f = adfCM[5];
     490               0 :             double ap = adfMatrix[0];
     491               0 :             double bp = adfMatrix[1];
     492               0 :             double cp = adfMatrix[2];
     493               0 :             double dp = adfMatrix[3];
     494               0 :             double ep = adfMatrix[4];
     495               0 :             double fp = adfMatrix[5];
     496               0 :             adfCM[0] = a*ap + b*cp;
     497               0 :             adfCM[1] = a*bp + b*dp;
     498               0 :             adfCM[2] = c*ap + d*cp;
     499               0 :             adfCM[3] = c*bp + d*dp;
     500               0 :             adfCM[4] = e*ap + f*cp + ep;
     501               0 :             adfCM[5] = e*bp + f*dp + fp;
     502               0 :         }
     503                 : 
     504            3068 :         void ApplyMatrix(double adfCoords[2])
     505                 :         {
     506            3068 :             double x = adfCoords[0];
     507            3068 :             double y = adfCoords[1];
     508                 : 
     509            3068 :             adfCoords[0] = x * adfCM[0] + y * adfCM[2] + adfCM[4];
     510            3068 :             adfCoords[1] = x * adfCM[1] + y * adfCM[3] + adfCM[5];
     511            3068 :         }
     512                 : };
     513                 : 
     514                 : /************************************************************************/
     515                 : /*                         PDFCoordsToSRSCoords()                       */
     516                 : /************************************************************************/
     517                 : 
     518            3356 : void OGRPDFDataSource::PDFCoordsToSRSCoords(double x, double y,
     519                 :                                             double& X, double &Y)
     520                 : {
     521            3356 :     x = x / dfPageWidth * nXSize;
     522            3356 :     y = (1 - y / dfPageHeight) * nYSize;
     523                 : 
     524            3356 :     X = adfGeoTransform[0] + x * adfGeoTransform[1] + y * adfGeoTransform[2];
     525            3356 :     Y = adfGeoTransform[3] + x * adfGeoTransform[4] + y * adfGeoTransform[5];
     526                 : 
     527            3356 :     if( fabs(X - (int)floor(X + 0.5)) < 1e-8 )
     528              28 :         X = (int)floor(X + 0.5);
     529            3356 :     if( fabs(Y - (int)floor(Y + 0.5)) < 1e-8 )
     530              30 :         Y = (int)floor(Y + 0.5);
     531            3356 : }
     532                 : 
     533                 : /************************************************************************/
     534                 : /*                            UnstackTokens()                           */
     535                 : /************************************************************************/
     536                 : 
     537            2924 : int OGRPDFDataSource::UnstackTokens(const CPLString& osToken,
     538                 :                                     std::stack<CPLString>& osTokenStack,
     539                 :                                     double* adfCoords)
     540                 : {
     541            2924 :     int nArgs = oMapOperators[osToken];
     542            9092 :     for(int i=0;i<nArgs;i++)
     543                 :     {
     544            6168 :         if (osTokenStack.empty())
     545                 :         {
     546               0 :             CPLDebug("PDF", "not enough arguments for %s", osToken.c_str());
     547               0 :             return FALSE;
     548                 :         }
     549            6168 :         adfCoords[nArgs-1-i] = atof(osTokenStack.top());
     550            6168 :         osTokenStack.pop();
     551                 :     }
     552            2924 :     return TRUE;
     553                 : }
     554                 : 
     555                 : /************************************************************************/
     556                 : /*                           ParseContent()                             */
     557                 : /************************************************************************/
     558                 : 
     559                 : #define NEW_SUBPATH -99
     560                 : #define CLOSE_SUBPATH -98
     561                 : #define FILL_SUBPATH -97
     562                 : 
     563             752 : void OGRPDFDataSource::ParseContent(const char* pszContent,
     564                 :                                     int nMCID,
     565                 :                                     GDALPDFObject* poResources,
     566                 :                                     int bInitBDCStack)
     567                 : {
     568             752 :     CPLString osToken;
     569                 :     char ch;
     570             752 :     std::stack<CPLString> osTokenStack;
     571             752 :     int bInString = FALSE;
     572             752 :     int nBDCLevel = 0;
     573             752 :     int nParenthesisLevel = 0;
     574             752 :     int nArrayLevel = 0;
     575             752 :     int nBTLevel = 0;
     576                 : 
     577             752 :     GraphicState oGS;
     578             752 :     std::stack<GraphicState> oGSStack;
     579                 : 
     580             752 :     std::vector<double> oCoords;
     581             752 :     int bHasFoundFill = FALSE;
     582             752 :     int bHasMultiPart = FALSE;
     583             752 :     int bHasRe = FALSE;
     584                 : 
     585             752 :     if (bInitBDCStack)
     586                 :     {
     587             744 :         osTokenStack.push("dummy");
     588             744 :         osTokenStack.push("dummy");
     589                 :     }
     590                 : 
     591           76280 :     while((ch = *pszContent) != '\0')
     592                 :     {
     593           75520 :         int bPushToken = FALSE;
     594                 : 
     595           75520 :         if (!bInString && ch == '%')
     596                 :         {
     597                 :             /* Skip comments until end-of-line */
     598               0 :             while((ch = *pszContent) != '\0')
     599                 :             {
     600               0 :                 if (ch == '\r' || ch == '\n')
     601               0 :                     break;
     602               0 :                 pszContent ++;
     603                 :             }
     604               0 :             if (ch == 0)
     605               0 :                 break;
     606                 :         }
     607           87096 :         else if (!bInString && (ch == ' ' || ch == '\r' || ch == '\n'))
     608                 :         {
     609           11576 :             bPushToken = TRUE;
     610                 :         }
     611                 : 
     612                 :         /* Ignore arrays */
     613           63944 :         else if (!bInString && osToken.size() == 0 && ch == '[')
     614                 :         {
     615               8 :             nArrayLevel ++;
     616                 :         }
     617           63936 :         else if (!bInString && nArrayLevel && osToken.size() == 0 && ch == ']')
     618                 :         {
     619               8 :             nArrayLevel --;
     620                 :         }
     621                 : 
     622           63928 :         else if (!bInString && osToken.size() == 0 && ch == '(')
     623                 :         {
     624               0 :             bInString = TRUE;
     625               0 :             nParenthesisLevel ++;
     626               0 :             osToken += ch;
     627                 :         }
     628           63928 :         else if (bInString && ch == '(')
     629                 :         {
     630               0 :             nParenthesisLevel ++;
     631               0 :             osToken += ch;
     632                 :         }
     633           63928 :         else if (bInString && ch == ')')
     634                 :         {
     635               0 :             nParenthesisLevel --;
     636               0 :             osToken += ch;
     637               0 :             if (nParenthesisLevel == 0)
     638                 :             {
     639               0 :                 bInString = FALSE;
     640               0 :                 bPushToken = TRUE;
     641                 :             }
     642                 :         }
     643                 :         else
     644                 :         {
     645           63928 :             osToken += ch;
     646                 :         }
     647                 : 
     648           75520 :         pszContent ++;
     649           75520 :         if (pszContent[0] == '\0')
     650               8 :             bPushToken = TRUE;
     651                 : 
     652           75520 :         if (bPushToken && osToken.size())
     653                 :         {
     654           11584 :             if (osToken == "BDC")
     655                 :             {
     656             744 :                 int nArgs = oMapOperators[osToken];
     657            2232 :                 for(int i=0;i<nArgs;i++)
     658                 :                 {
     659            1488 :                     if (osTokenStack.empty())
     660                 :                     {
     661                 :                         CPLDebug("PDF",
     662                 :                                     "not enough arguments for %s",
     663               0 :                                     osToken.c_str());
     664                 :                         return;
     665                 :                     }
     666            1488 :                     osTokenStack.pop();
     667                 :                 }
     668             744 :                 nBDCLevel ++;
     669                 :             }
     670           10840 :             else if (osToken == "EMC")
     671                 :             {
     672             744 :                 nBDCLevel --;
     673             744 :                 if (nBDCLevel == 0)
     674             744 :                     break;
     675                 :             }
     676                 : 
     677                 :             /* Ignore any text stuff */
     678           10096 :             else if (osToken == "BT")
     679               0 :                 nBTLevel ++;
     680           10096 :             else if (osToken == "ET")
     681                 :             {
     682               0 :                 nBTLevel --;
     683               0 :                 if (nBTLevel < 0)
     684                 :                     return;
     685                 :             }
     686           10096 :             else if (!nArrayLevel && !nBTLevel)
     687                 :             {
     688           10096 :                 if (osToken == "q")
     689                 :                 {
     690               8 :                     oGSStack.push(oGS);
     691                 :                 }
     692           10088 :                 else if (osToken == "Q")
     693                 :                 {
     694               8 :                     if (oGSStack.empty())
     695                 :                     {
     696               0 :                         CPLDebug("PDF", "not enough arguments for %s", osToken.c_str());
     697                 :                         return;
     698                 :                     }
     699                 : 
     700               8 :                     oGS = oGSStack.top();
     701               8 :                     oGSStack.pop();
     702                 :                 }
     703           10080 :                 else if (osToken == "cm")
     704                 :                 {
     705                 :                     double adfMatrix[6];
     706               0 :                     for(int i=0;i<6;i++)
     707                 :                     {
     708               0 :                         if (osTokenStack.empty())
     709                 :                         {
     710               0 :                             CPLDebug("PDF", "not enough arguments for %s", osToken.c_str());
     711                 :                             return;
     712                 :                         }
     713               0 :                         adfMatrix[6-1-i] = atof(osTokenStack.top());
     714               0 :                         osTokenStack.pop();
     715                 :                     }
     716                 : 
     717               0 :                     oGS.MultiplyBy(adfMatrix);
     718                 :                 }
     719           10080 :                 else if (osToken == "b" ||
     720                 :                          osToken == "b*")
     721                 :                 {
     722               6 :                     if (!(oCoords.size() > 0 &&
     723                 :                           oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
     724                 :                           oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
     725                 :                     {
     726               2 :                         oCoords.push_back(CLOSE_SUBPATH);
     727               2 :                         oCoords.push_back(CLOSE_SUBPATH);
     728                 :                     }
     729               6 :                     oCoords.push_back(FILL_SUBPATH);
     730               6 :                     oCoords.push_back(FILL_SUBPATH);
     731               6 :                     bHasFoundFill = TRUE;
     732                 :                 }
     733           10074 :                 else if (osToken == "B" ||
     734                 :                          osToken == "B*" ||
     735                 :                          osToken == "f" ||
     736                 :                          osToken == "F" ||
     737                 :                          osToken == "f*")
     738                 :                 {
     739             398 :                     oCoords.push_back(FILL_SUBPATH);
     740             398 :                     oCoords.push_back(FILL_SUBPATH);
     741             398 :                     bHasFoundFill = TRUE;
     742                 :                 }
     743            9676 :                 else if (osToken == "h")
     744                 :                 {
     745               6 :                     oCoords.push_back(CLOSE_SUBPATH);
     746               6 :                     oCoords.push_back(CLOSE_SUBPATH);
     747                 :                 }
     748            9670 :                 else if (osToken == "n")
     749                 :                 {
     750               0 :                     oCoords.resize(0);
     751                 :                 }
     752            9670 :                 else if (osToken == "m" || osToken == "l")
     753                 :                 {
     754                 :                     double adfCoords[2];
     755            2772 :                     if (!UnstackTokens(osToken, osTokenStack, adfCoords))
     756                 :                         return;
     757                 : 
     758            2772 :                     if (osToken == "m")
     759                 :                     {
     760             664 :                         if (oCoords.size() != 0)
     761              64 :                             bHasMultiPart = TRUE;
     762             664 :                         oCoords.push_back(NEW_SUBPATH);
     763             664 :                         oCoords.push_back(NEW_SUBPATH);
     764                 :                     }
     765                 : 
     766            2772 :                     oGS.ApplyMatrix(adfCoords);
     767            2772 :                     oCoords.push_back(adfCoords[0]);
     768            2772 :                     oCoords.push_back(adfCoords[1]);
     769                 :                 }
     770            6898 :                 else if (osToken == "c") /* Bezier curve */
     771                 :                 {
     772                 :                     double adfCoords[6];
     773               8 :                     if (!UnstackTokens(osToken, osTokenStack, adfCoords))
     774                 :                         return;
     775                 : 
     776               8 :                     oGS.ApplyMatrix(adfCoords + 4);
     777               8 :                     oCoords.push_back(adfCoords[4]);
     778               8 :                     oCoords.push_back(adfCoords[5]);
     779                 :                 }
     780            6890 :                 else if (osToken == "v" || osToken == "y") /* Bezier curve */
     781                 :                 {
     782                 :                     double adfCoords[4];
     783               0 :                     if (!UnstackTokens(osToken, osTokenStack, adfCoords))
     784                 :                         return;
     785                 : 
     786               0 :                     oGS.ApplyMatrix(adfCoords + 2);
     787               0 :                     oCoords.push_back(adfCoords[2]);
     788               0 :                     oCoords.push_back(adfCoords[3]);
     789                 :                 }
     790            6890 :                 else if (osToken == "re") /* Rectangle */
     791                 :                 {
     792                 :                     double adfCoords[4];
     793             144 :                     if (!UnstackTokens(osToken, osTokenStack, adfCoords))
     794                 :                         return;
     795                 : 
     796             144 :                     adfCoords[2] += adfCoords[0];
     797             144 :                     adfCoords[3] += adfCoords[1];
     798                 : 
     799             144 :                     oGS.ApplyMatrix(adfCoords);
     800             144 :                     oGS.ApplyMatrix(adfCoords + 2);
     801                 : 
     802             144 :                     if (oCoords.size() != 0)
     803               0 :                         bHasMultiPart = TRUE;
     804             144 :                     oCoords.push_back(NEW_SUBPATH);
     805             144 :                     oCoords.push_back(NEW_SUBPATH);
     806             144 :                     oCoords.push_back(adfCoords[0]);
     807             144 :                     oCoords.push_back(adfCoords[1]);
     808             144 :                     oCoords.push_back(adfCoords[2]);
     809             144 :                     oCoords.push_back(adfCoords[1]);
     810             144 :                     oCoords.push_back(adfCoords[2]);
     811             144 :                     oCoords.push_back(adfCoords[3]);
     812             144 :                     oCoords.push_back(adfCoords[0]);
     813             144 :                     oCoords.push_back(adfCoords[3]);
     814             144 :                     oCoords.push_back(CLOSE_SUBPATH);
     815             144 :                     oCoords.push_back(CLOSE_SUBPATH);
     816             144 :                     bHasRe = TRUE;
     817                 :                 }
     818                 : 
     819            6746 :                 else if (osToken == "Do")
     820                 :                 {
     821               8 :                     if (osTokenStack.empty())
     822                 :                     {
     823                 :                         CPLDebug("PDF",
     824                 :                                  "not enough arguments for %s",
     825               0 :                                  osToken.c_str());
     826                 :                         return;
     827                 :                     }
     828                 : 
     829               8 :                     CPLString osObjectName = osTokenStack.top();
     830               8 :                     osTokenStack.pop();
     831                 : 
     832               8 :                     if (osObjectName[0] != '/')
     833                 :                         return;
     834                 : 
     835               8 :                     if (poResources == NULL)
     836                 :                         return;
     837                 : 
     838                 :                     GDALPDFObject* poXObject =
     839               8 :                         poResources->GetDictionary()->Get("XObject");
     840              16 :                     if (poXObject == NULL ||
     841               8 :                         poXObject->GetType() != PDFObjectType_Dictionary)
     842                 :                         return;
     843                 : 
     844                 :                     GDALPDFObject* poObject =
     845               8 :                         poXObject->GetDictionary()->Get(osObjectName.c_str() + 1);
     846               8 :                     if (poObject == NULL)
     847                 :                         return;
     848                 : 
     849               8 :                     GDALPDFStream* poStream = poObject->GetStream();
     850               8 :                     if (!poStream)
     851                 :                         return;
     852                 : 
     853               8 :                     char* pszStr = poStream->GetBytes();
     854               8 :                     ParseContent(pszStr, nMCID, NULL, FALSE);
     855               8 :                     CPLFree(pszStr);
     856                 :                 }
     857            6738 :                 else if (oMapOperators.find(osToken) != oMapOperators.end())
     858                 :                 {
     859             466 :                     int nArgs = oMapOperators[osToken];
     860             466 :                     if (nArgs < 0)
     861                 :                     {
     862               0 :                         while( !osTokenStack.empty() )
     863                 :                         {
     864               0 :                             CPLString osTopToken = osTokenStack.top();
     865               0 :                             if (oMapOperators.find(osTopToken) != oMapOperators.end())
     866                 :                                 break;
     867               0 :                             osTokenStack.pop();
     868                 :                         }
     869                 :                     }
     870                 :                     else
     871                 :                     {
     872             562 :                         for(int i=0;i<nArgs;i++)
     873                 :                         {
     874              96 :                             if (osTokenStack.empty())
     875                 :                             {
     876                 :                                 CPLDebug("PDF",
     877                 :                                         "not enough arguments for %s",
     878               0 :                                         osToken.c_str());
     879                 :                                 return;
     880                 :                             }
     881              96 :                             osTokenStack.pop();
     882                 :                         }
     883                 :                     }
     884                 :                 }
     885                 :                 else
     886                 :                 {
     887                 :                     //printf("%s\n", osToken.c_str());
     888            6272 :                     osTokenStack.push(osToken);
     889                 :                 }
     890                 :             }
     891                 : 
     892           10840 :             osToken = "";
     893                 :         }
     894                 :     }
     895                 : 
     896             752 :     if (!osTokenStack.empty())
     897                 :     {
     898               0 :         while(!osTokenStack.empty())
     899                 :         {
     900                 :             CPLDebug("PDF",
     901                 :                      "Remaing values in stack : %s",
     902               0 :                      osTokenStack.top().c_str());
     903               0 :             osTokenStack.pop();
     904                 :         }
     905                 :         return;
     906                 :     }
     907                 : 
     908             752 :     if (!oCoords.size())
     909                 :         return;
     910                 : 
     911                 : 
     912             744 :     OGRGeometry* poGeom = NULL;
     913             744 :     if (!bHasFoundFill)
     914                 :     {
     915             340 :         OGRLineString* poLS = NULL;
     916             340 :         OGRMultiLineString* poMLS = NULL;
     917             340 :         if (bHasMultiPart)
     918                 :         {
     919              10 :             poMLS = new OGRMultiLineString();
     920              10 :             poGeom = poMLS;
     921                 :         }
     922                 : 
     923            1808 :         for(size_t i=0;i<oCoords.size();i+=2)
     924                 :         {
     925            1468 :             if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
     926                 :             {
     927             402 :                 poLS = new OGRLineString();
     928             402 :                 if (poMLS)
     929              72 :                     poMLS->addGeometryDirectly(poLS);
     930                 :                 else
     931             330 :                     poGeom = poLS;
     932                 :             }
     933            1066 :             else if (oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH)
     934                 :             {
     935               0 :                 if (poLS && poLS->getNumPoints() >= 2 &&
     936                 :                     !(poLS->getX(0) == poLS->getX(poLS->getNumPoints()-1) &&
     937                 :                         poLS->getY(0) == poLS->getY(poLS->getNumPoints()-1)))
     938                 :                 {
     939               0 :                     poLS->addPoint(poLS->getX(0), poLS->getY(0));
     940                 :                 }
     941                 :             }
     942            1066 :             else if (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH)
     943                 :             {
     944                 :                 /* Should not happen */
     945                 :             }
     946                 :             else
     947                 :             {
     948            1066 :                 if (poLS)
     949                 :                 {
     950                 :                     double X, Y;
     951            1066 :                     PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
     952                 : 
     953            1066 :                     poLS->addPoint(X, Y);
     954                 :                 }
     955                 :             }
     956                 :         }
     957                 :     }
     958                 :     else
     959                 :     {
     960             404 :         OGRLinearRing* poLS = NULL;
     961             404 :         int nPolys = 0;
     962             404 :         OGRGeometry** papoPoly = NULL;
     963                 : 
     964            3364 :         for(size_t i=0;i<oCoords.size();i+=2)
     965                 :         {
     966            3106 :             if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
     967                 :             {
     968             406 :                 delete poLS;
     969             406 :                 poLS = new OGRLinearRing();
     970                 :             }
     971            2700 :             else if ((oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH) ||
     972                 :                         (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH))
     973                 :             {
     974             410 :                 if (poLS)
     975                 :                 {
     976             406 :                     poLS->closeRings();
     977                 : 
     978                 :                     /* Recognize points as outputed by GDAL */
     979             406 :                     if (nPolys == 0 &&
     980                 :                         poLS->getNumPoints() == 5 &&
     981                 :                         poLS->getY(0) == poLS->getY(2) &&
     982                 :                         poLS->getX(1) == poLS->getX(3) &&
     983                 :                         fabs((poLS->getX(0) + poLS->getX(2)) / 2 - poLS->getX(1)) < 1e-5 &&
     984                 :                         fabs((poLS->getY(1) + poLS->getY(3)) / 2 - poLS->getY(0)) < 1e-5)
     985                 :                     {
     986                 :                         poGeom = new OGRPoint((poLS->getX(0) + poLS->getX(2)) / 2,
     987               2 :                                                 (poLS->getY(1) + poLS->getY(3)) / 2);
     988               2 :                         break;
     989                 :                     }
     990                 :                     /* ESRI points */
     991             404 :                     else if (bHasRe && oCoords.size() == 14 && nPolys == 0 &&
     992                 :                                 poLS->getNumPoints() == 5 &&
     993                 :                                 poLS->getY(0) == poLS->getY(1) &&
     994                 :                                 poLS->getX(1) == poLS->getX(2) &&
     995                 :                                 poLS->getY(2) == poLS->getY(3) &&
     996                 :                                 poLS->getX(3) == poLS->getX(0))
     997                 :                     {
     998                 :                         poGeom = new OGRPoint((poLS->getX(0) + poLS->getX(1)) / 2,
     999             144 :                                                 (poLS->getY(0) + poLS->getY(2)) / 2);
    1000             144 :                         break;
    1001                 :                     }
    1002                 :                     else
    1003                 :                     {
    1004             260 :                         if (poLS->getNumPoints() >= 3)
    1005                 :                         {
    1006             260 :                             OGRPolygon* poPoly =  new OGRPolygon();
    1007             260 :                             poPoly->addRingDirectly(poLS);
    1008             260 :                             poLS = NULL;
    1009                 : 
    1010             260 :                             papoPoly = (OGRGeometry**) CPLRealloc(papoPoly, (nPolys + 1) * sizeof(OGRGeometry*));
    1011             260 :                             papoPoly[nPolys ++] = poPoly;
    1012                 :                         }
    1013                 :                         else
    1014                 :                         {
    1015               0 :                             delete poLS;
    1016               0 :                             poLS = NULL;
    1017                 :                         }
    1018                 :                     }
    1019                 :                 }
    1020                 :             }
    1021                 :             else
    1022                 :             {
    1023            2290 :                 if (poLS)
    1024                 :                 {
    1025                 :                     double X, Y;
    1026            2290 :                     PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
    1027                 : 
    1028            2290 :                     poLS->addPoint(X, Y);
    1029                 :                 }
    1030                 :             }
    1031                 :         }
    1032                 : 
    1033             404 :         delete poLS;
    1034                 : 
    1035                 :         int bIsValidGeometry;
    1036             408 :         if (nPolys == 2 &&
    1037               2 :             ((OGRPolygon*)papoPoly[0])->getNumInteriorRings() == 0 &&
    1038               2 :             ((OGRPolygon*)papoPoly[1])->getNumInteriorRings() == 0)
    1039                 :         {
    1040               2 :             OGRLinearRing* poRing0 = ((OGRPolygon*)papoPoly[0])->getExteriorRing();
    1041               2 :             OGRLinearRing* poRing1 = ((OGRPolygon*)papoPoly[1])->getExteriorRing();
    1042               2 :             if (poRing0->getNumPoints() == poRing1->getNumPoints())
    1043                 :             {
    1044               2 :                 int bSameRing = TRUE;
    1045               2 :                 for(int i=0;i<poRing0->getNumPoints();i++)
    1046                 :                 {
    1047               2 :                     if (poRing0->getX(i) != poRing1->getX(i))
    1048                 :                     {
    1049               2 :                         bSameRing = FALSE;
    1050               2 :                         break;
    1051                 :                     }
    1052               0 :                     if (poRing0->getY(i) != poRing1->getY(i))
    1053                 :                     {
    1054               0 :                         bSameRing = FALSE;
    1055               0 :                         break;
    1056                 :                     }
    1057                 :                 }
    1058                 : 
    1059                 :                 /* Just keep on ring if they are identical */
    1060               2 :                 if (bSameRing)
    1061                 :                 {
    1062               0 :                     delete papoPoly[1];
    1063               0 :                     nPolys = 1;
    1064                 :                 }
    1065                 :             }
    1066                 :         }
    1067             404 :         if (nPolys)
    1068                 :         {
    1069                 :             poGeom = OGRGeometryFactory::organizePolygons(
    1070             258 :                     papoPoly, nPolys, &bIsValidGeometry, NULL);
    1071                 :         }
    1072             404 :         CPLFree(papoPoly);
    1073                 :     }
    1074                 : 
    1075                 :     /* Save geometry in map */
    1076             744 :     oMapMCID[nMCID] = poGeom;
    1077                 : }
    1078                 : 
    1079                 : /************************************************************************/
    1080                 : /*                          ExploreContents()                           */
    1081                 : /************************************************************************/
    1082                 : 
    1083              10 : void OGRPDFDataSource::ExploreContents(GDALPDFObject* poObj,
    1084                 :                                        GDALPDFObject* poResources)
    1085                 : {
    1086              10 :     if (poObj->GetType() == PDFObjectType_Array)
    1087                 :     {
    1088               2 :         GDALPDFArray* poArray = poObj->GetArray();
    1089               8 :         for(int i=0;i<poArray->GetLength();i++)
    1090               6 :             ExploreContents(poArray->Get(i), poResources);
    1091                 :     }
    1092                 : 
    1093              10 :     if (poObj->GetType() != PDFObjectType_Dictionary)
    1094               2 :         return;
    1095                 : 
    1096               8 :     GDALPDFStream* poStream = poObj->GetStream();
    1097               8 :     if (!poStream)
    1098               0 :         return;
    1099                 : 
    1100               8 :     char* pszStr = poStream->GetBytes();
    1101               8 :     const char* pszMCID = (const char*) pszStr;
    1102             760 :     while((pszMCID = strstr(pszMCID, "/MCID")) != NULL)
    1103                 :     {
    1104             744 :         const char* pszBDC = strstr(pszMCID, "BDC");
    1105             744 :         if (pszBDC)
    1106                 :         {
    1107             744 :             int nMCID = atoi(pszMCID + 6);
    1108             744 :             if (GetGeometryFromMCID(nMCID) == NULL)
    1109             744 :                 ParseContent(pszBDC, nMCID, poResources, TRUE);
    1110                 :         }
    1111             744 :         pszMCID += 5;
    1112                 :     }
    1113               8 :     CPLFree(pszStr);
    1114                 : }
    1115                 : 
    1116                 : /************************************************************************/
    1117                 : /*                               Open()                                 */
    1118                 : /************************************************************************/
    1119                 : 
    1120               4 : int OGRPDFDataSource::Open( const char * pszName)
    1121                 : {
    1122               4 :     this->pszName = CPLStrdup(pszName);
    1123                 : 
    1124               4 :     poGDAL_DS = GDALPDFOpen(pszName, GA_ReadOnly);
    1125               4 :     if (poGDAL_DS == NULL)
    1126               0 :         return FALSE;
    1127                 : 
    1128               4 :     const char* pszPageObj = poGDAL_DS->GetMetadataItem("PDF_PAGE_OBJECT");
    1129               4 :     if (pszPageObj)
    1130               4 :         sscanf(pszPageObj, "%p", &poPageObj);
    1131               4 :     if (poPageObj == NULL || poPageObj->GetType() != PDFObjectType_Dictionary)
    1132               0 :         return FALSE;
    1133                 : 
    1134               4 :     GDALPDFObject* poMediaBox = poPageObj->GetDictionary()->Get("MediaBox");
    1135              12 :     if (poMediaBox == NULL || poMediaBox->GetType() != PDFObjectType_Array ||
    1136               8 :         poMediaBox->GetArray()->GetLength() != 4)
    1137               0 :         return FALSE;
    1138                 : 
    1139               4 :     if (poMediaBox->GetArray()->Get(2)->GetType() == PDFObjectType_Real)
    1140               2 :         dfPageWidth = poMediaBox->GetArray()->Get(2)->GetReal();
    1141               2 :     else if (poMediaBox->GetArray()->Get(2)->GetType() == PDFObjectType_Int)
    1142               2 :         dfPageWidth = poMediaBox->GetArray()->Get(2)->GetInt();
    1143                 :     else
    1144               0 :         return FALSE;
    1145                 : 
    1146               4 :     if (poMediaBox->GetArray()->Get(3)->GetType() == PDFObjectType_Real)
    1147               2 :         dfPageHeight = poMediaBox->GetArray()->Get(3)->GetReal();
    1148               2 :     else if (poMediaBox->GetArray()->Get(3)->GetType() == PDFObjectType_Int)
    1149               2 :         dfPageHeight = poMediaBox->GetArray()->Get(3)->GetInt();
    1150                 :     else
    1151               0 :         return FALSE;
    1152                 : 
    1153               4 :     GDALPDFObject* poContents = poPageObj->GetDictionary()->Get("Contents");
    1154               4 :     if (poContents == NULL)
    1155               0 :         return FALSE;
    1156                 : 
    1157               6 :     if (poContents->GetType() != PDFObjectType_Dictionary &&
    1158               2 :         poContents->GetType() != PDFObjectType_Array)
    1159               0 :         return FALSE;
    1160                 : 
    1161               4 :     GDALPDFObject* poResources = poPageObj->GetDictionary()->Get("Resources");
    1162               4 :     if (poResources == NULL || poResources->GetType() != PDFObjectType_Dictionary)
    1163               0 :         return FALSE;
    1164                 :     
    1165               4 :     const char* pszCatalog = poGDAL_DS->GetMetadataItem("PDF_CATALOG_OBJECT");
    1166               4 :     if (pszCatalog)
    1167               4 :         sscanf(pszCatalog, "%p", &poCatalogObj);
    1168               4 :     if (poCatalogObj == NULL || poCatalogObj->GetType() != PDFObjectType_Dictionary)
    1169               0 :         return FALSE;
    1170                 : 
    1171               4 :     GDALPDFObject* poStructTreeRoot = poCatalogObj->GetDictionary()->Get("StructTreeRoot");
    1172               4 :     if (poStructTreeRoot == NULL || poStructTreeRoot->GetType() != PDFObjectType_Dictionary)
    1173               0 :         return FALSE;
    1174                 : 
    1175               4 :     nXSize = poGDAL_DS->GetRasterXSize();
    1176               4 :     nYSize = poGDAL_DS->GetRasterYSize();
    1177               4 :     poGDAL_DS->GetGeoTransform(adfGeoTransform);
    1178                 : 
    1179               4 :     ExploreContents(poContents, poResources);
    1180               4 :     ExploreTree(poStructTreeRoot);
    1181                 : 
    1182               4 :     CleanupIntermediateResources();
    1183                 : 
    1184               4 :     int bEmptyDS = TRUE;
    1185               4 :     for(int i=0;i<nLayers;i++)
    1186                 :     {
    1187               4 :         if (papoLayers[i]->GetFeatureCount() != 0)
    1188                 :         {
    1189               4 :             bEmptyDS = FALSE;
    1190               4 :             break;
    1191                 :         }
    1192                 :     }
    1193               4 :     if (bEmptyDS)
    1194               0 :         return FALSE;
    1195                 : 
    1196               4 :     return TRUE;
    1197                 : }
    1198                 : 
    1199                 : /************************************************************************/
    1200                 : /*                               Create()                               */
    1201                 : /************************************************************************/
    1202                 : 
    1203               2 : int OGRPDFDataSource::Create( const char * pszName, char **papszOptions )
    1204                 : {
    1205               2 :     this->pszName = CPLStrdup(pszName);
    1206               2 :     this->papszOptions = CSLDuplicate(papszOptions);
    1207               2 :     bWritable = TRUE;
    1208                 : 
    1209               2 :     return TRUE;
    1210                 : }
    1211                 : 
    1212                 : /************************************************************************/
    1213                 : /*                            CreateLayer()                             */
    1214                 : /************************************************************************/
    1215                 : 
    1216                 : OGRLayer *
    1217               2 : OGRPDFDataSource::CreateLayer( const char * pszLayerName,
    1218                 :                                 OGRSpatialReference *poSRS,
    1219                 :                                 OGRwkbGeometryType eType,
    1220                 :                                 char ** papszOptions )
    1221                 : 
    1222                 : {
    1223                 : /* -------------------------------------------------------------------- */
    1224                 : /*      Create the layer object.                                        */
    1225                 : /* -------------------------------------------------------------------- */
    1226               2 :     OGRLayer* poLayer = new OGRPDFLayer(this, pszLayerName, poSRS, eType);
    1227                 : 
    1228               2 :     papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
    1229               2 :     papoLayers[nLayers] = poLayer;
    1230               2 :     nLayers ++;
    1231                 : 
    1232               2 :     return poLayer;
    1233                 : }
    1234                 : 
    1235                 : /************************************************************************/
    1236                 : /*                            SyncToDisk()                              */
    1237                 : /************************************************************************/
    1238                 : 
    1239               6 : OGRErr OGRPDFDataSource::SyncToDisk()
    1240                 : {
    1241               6 :     if (nLayers == 0 || !bModified || !bWritable)
    1242               4 :         return OGRERR_NONE;
    1243                 : 
    1244               2 :     bModified = FALSE;
    1245                 : 
    1246               2 :     OGREnvelope sGlobalExtent;
    1247               2 :     int bHasExtent = FALSE;
    1248               4 :     for(int i=0;i<nLayers;i++)
    1249                 :     {
    1250               2 :         OGREnvelope sExtent;
    1251               2 :         if (papoLayers[i]->GetExtent(&sExtent) == OGRERR_NONE)
    1252                 :         {
    1253               2 :             bHasExtent = TRUE;
    1254               2 :             sGlobalExtent.Merge(sExtent);
    1255                 :         }
    1256                 :     }
    1257               2 :     if (!bHasExtent ||
    1258                 :         sGlobalExtent.MinX == sGlobalExtent.MaxX ||
    1259                 :         sGlobalExtent.MinY == sGlobalExtent.MaxY)
    1260                 :     {
    1261                 :         CPLError(CE_Failure, CPLE_AppDefined,
    1262               0 :                  "Cannot compute spatial extent of features");
    1263               0 :         return OGRERR_FAILURE;
    1264                 :     }
    1265                 : 
    1266               2 :     PDFCompressMethod eStreamCompressMethod = COMPRESS_DEFLATE;
    1267               2 :     const char* pszStreamCompressMethod = CSLFetchNameValue(papszOptions, "STREAM_COMPRESS");
    1268               2 :     if (pszStreamCompressMethod)
    1269                 :     {
    1270               0 :         if( EQUAL(pszStreamCompressMethod, "NONE") )
    1271               0 :             eStreamCompressMethod = COMPRESS_NONE;
    1272               0 :         else if( EQUAL(pszStreamCompressMethod, "DEFLATE") )
    1273               0 :             eStreamCompressMethod = COMPRESS_DEFLATE;
    1274                 :         else
    1275                 :         {
    1276                 :             CPLError( CE_Warning, CPLE_NotSupported,
    1277               0 :                     "Unsupported value for STREAM_COMPRESS.");
    1278                 :         }
    1279                 :     }
    1280                 : 
    1281                 :     const char* pszGEO_ENCODING =
    1282               2 :         CSLFetchNameValueDef(papszOptions, "GEO_ENCODING", "ISO32000");
    1283                 : 
    1284               2 :     double dfDPI = atof(CSLFetchNameValueDef(papszOptions, "DPI", "72"));
    1285               2 :     if (dfDPI < 72.0)
    1286               0 :         dfDPI = 72.0;
    1287                 : 
    1288               2 :     const char* pszNEATLINE = CSLFetchNameValue(papszOptions, "NEATLINE");
    1289                 : 
    1290               2 :     int nMargin = atoi(CSLFetchNameValueDef(papszOptions, "MARGIN", "0"));
    1291                 : 
    1292                 :     PDFMargins sMargins;
    1293               2 :     sMargins.nLeft = nMargin;
    1294               2 :     sMargins.nRight = nMargin;
    1295               2 :     sMargins.nTop = nMargin;
    1296               2 :     sMargins.nBottom = nMargin;
    1297                 : 
    1298               2 :     const char* pszLeftMargin = CSLFetchNameValue(papszOptions, "LEFT_MARGIN");
    1299               2 :     if (pszLeftMargin) sMargins.nLeft = atoi(pszLeftMargin);
    1300                 : 
    1301               2 :     const char* pszRightMargin = CSLFetchNameValue(papszOptions, "RIGHT_MARGIN");
    1302               2 :     if (pszRightMargin) sMargins.nRight = atoi(pszRightMargin);
    1303                 : 
    1304               2 :     const char* pszTopMargin = CSLFetchNameValue(papszOptions, "TOP_MARGIN");
    1305               2 :     if (pszTopMargin) sMargins.nTop = atoi(pszTopMargin);
    1306                 : 
    1307               2 :     const char* pszBottomMargin = CSLFetchNameValue(papszOptions, "BOTTOM_MARGIN");
    1308               2 :     if (pszBottomMargin) sMargins.nBottom = atoi(pszBottomMargin);
    1309                 : 
    1310               2 :     const char* pszExtraImages = CSLFetchNameValue(papszOptions, "EXTRA_IMAGES");
    1311               2 :     const char* pszExtraStream = CSLFetchNameValue(papszOptions, "EXTRA_STREAM");
    1312               2 :     const char* pszExtraLayerName = CSLFetchNameValue(papszOptions, "EXTRA_LAYER_NAME");
    1313                 : 
    1314               2 :     const char* pszOGRDisplayField = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_FIELD");
    1315               2 :     int bWriteOGRAttributes = CSLFetchBoolean(papszOptions, "OGR_WRITE_ATTRIBUTES", TRUE);
    1316                 : 
    1317                 : /* -------------------------------------------------------------------- */
    1318                 : /*      Create file.                                                    */
    1319                 : /* -------------------------------------------------------------------- */
    1320               2 :     VSILFILE* fp = VSIFOpenL(pszName, "wb");
    1321               2 :     if( fp == NULL )
    1322                 :     {
    1323                 :         CPLError( CE_Failure, CPLE_OpenFailed,
    1324                 :                   "Unable to create PDF file %s.\n",
    1325               0 :                   pszName );
    1326               0 :         return OGRERR_FAILURE;
    1327                 :     }
    1328                 : 
    1329               2 :     GDALPDFWriter oWriter(fp);
    1330                 : 
    1331               2 :     double dfRatio = (sGlobalExtent.MaxY - sGlobalExtent.MinY) / (sGlobalExtent.MaxX - sGlobalExtent.MinX);
    1332                 : 
    1333                 :     int nWidth, nHeight;
    1334                 : 
    1335               2 :     if (dfRatio < 1)
    1336                 :     {
    1337               0 :         nWidth = 1024;
    1338               0 :         nHeight = nWidth * dfRatio;
    1339                 :     }
    1340                 :     else
    1341                 :     {
    1342               2 :         nHeight = 1024;
    1343               2 :         nWidth = nHeight / dfRatio;
    1344                 :     }
    1345                 : 
    1346               2 :     GDALDataset* poSrcDS = MEMDataset::Create( "MEM:::", nWidth, nHeight, 0, GDT_Byte, NULL );
    1347                 : 
    1348                 :     double adfGeoTransform[6];
    1349               2 :     adfGeoTransform[0] = sGlobalExtent.MinX;
    1350               2 :     adfGeoTransform[1] = (sGlobalExtent.MaxX - sGlobalExtent.MinX) / nWidth;
    1351               2 :     adfGeoTransform[2] = 0;
    1352               2 :     adfGeoTransform[3] = sGlobalExtent.MaxY;
    1353               2 :     adfGeoTransform[4] = 0;
    1354               2 :     adfGeoTransform[5] = - (sGlobalExtent.MaxY - sGlobalExtent.MinY) / nHeight;
    1355                 : 
    1356               2 :     poSrcDS->SetGeoTransform(adfGeoTransform);
    1357                 : 
    1358               2 :     OGRSpatialReference* poSRS = papoLayers[0]->GetSpatialRef();
    1359               2 :     if (poSRS)
    1360                 :     {
    1361               2 :         char* pszWKT = NULL;
    1362               2 :         poSRS->exportToWkt(&pszWKT);
    1363               2 :         poSrcDS->SetProjection(pszWKT);
    1364               2 :         CPLFree(pszWKT);
    1365                 :     }
    1366                 : 
    1367               2 :     oWriter.SetInfo(poSrcDS, papszOptions);
    1368                 : 
    1369                 :     oWriter.StartPage(poSrcDS,
    1370                 :                       dfDPI,
    1371                 :                       pszGEO_ENCODING,
    1372                 :                       pszNEATLINE,
    1373                 :                       &sMargins,
    1374                 :                       eStreamCompressMethod,
    1375               2 :                       bWriteOGRAttributes);
    1376                 : 
    1377               2 :     int iObj = 0;
    1378               4 :     for(int i=0;i<nLayers;i++)
    1379                 :     {
    1380                 :         GDALPDFLayerDesc osVectorDesc =
    1381               4 :             oWriter.StartOGRLayer(papoLayers[i]->GetName(),
    1382               6 :                                   bWriteOGRAttributes);
    1383                 : 
    1384               2 :         int iObjLayer = 0;
    1385              10 :         for(int j=0;j<papoLayers[i]->GetFeatureCount();j++)
    1386                 :         {
    1387               8 :             OGRFeature* poFeature = papoLayers[i]->GetFeature(j);
    1388                 : 
    1389                 :             oWriter.WriteOGRFeature(osVectorDesc,
    1390                 :                                     (OGRFeatureH) poFeature,
    1391                 :                                     pszOGRDisplayField,
    1392                 :                                     bWriteOGRAttributes,
    1393                 :                                     iObj,
    1394               8 :                                     iObjLayer);
    1395                 : 
    1396               8 :             delete poFeature;
    1397                 :         }
    1398                 : 
    1399               2 :         oWriter.EndOGRLayer(osVectorDesc);
    1400                 :     }
    1401                 : 
    1402                 : 
    1403                 :     oWriter.EndPage(pszExtraImages,
    1404                 :                     pszExtraStream,
    1405               2 :                     pszExtraLayerName);
    1406                 : 
    1407               2 :     oWriter.Close();
    1408                 : 
    1409               2 :     delete poSrcDS;
    1410                 : 
    1411               2 :     return OGRERR_NONE;
    1412                 : }

Generated by: LCOV version 1.7